unit nProcess;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, nStrings, JwaWinType, JwaWinBase, JwaTlHelp32;
type
TIntervStruct = class
private
Map: TList;
procedure FreeMap;
function GetCount: integer;
function GetInterval:TFileTime;
public
InfoList: TList;
UpdateTime:TFileTime;
PrevTime:TFileTime;
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure MakeMap;
procedure SetupTime;
function FindTime(id: DWORD; out time: FileTime):boolean;
property Count: integer read GetCount;
property Interval:TFileTime read GetInterval;
end;
function KillProcessByName(appname:UnicodeString):Boolean;
function FirstModuleName(hProcess: THandle):AnsiString;
procedure modules_list_PsAPI(modlist:TList; id: DWORD);
procedure modules_list_TH32(modlist:TList; id: DWORD);
procedure thread_list_TH32(var Threads: TIntervStruct; threadlist:TList; id: DWORD);
type
PMapElem = ^TMapElem;
TMapElem = record
id: DWORD;
ProcessTime:TFileTime;
end;
TCommInfo = class
public
procedure EssenceTo(MapElem: PMapElem); virtual; abstract;
end;
TModInfo = record
N: integer;
Name: string;
Dir: string;
Size: DWORD;
Base: pointer;
Entry: pointer;
end;
PModInfo = ^TModInfo;
PDriverInfo = ^TDriverInfo;
TDriverInfo = record
name:string;
dir:string;
addr:DWORD;
end;
TThreadInfo = class(TCommInfo)
public
Id:DWORD;
BasePri: Longint;
DeltaPri: Longint;
CreationTime:TFileTime;
KernelTime:TFileTime;
ProcessTime:TFileTime;
PercCpu:single;
PercCpuTotal:single;
procedure EssenceTo(MapElem: PMapElem); override;
end;
PProcessEntry32 = ^TProcessEntry32;
TProcessInfo = class(TCommInfo)
public
name1: AnsiString;
dir: AnsiString;
processID: DWORD;
cntThreads: DWORD;
parentID: DWORD;
memSize: DWORD;//NT
CreationTime: TFileTime;//for NT time, for 95 number
KernelTime: TFileTime;
ProcessTime: TFileTime;
PercCpu: single;
PercCpuTotal: single;
priority: word;
classProc: byte;
destructor Destroy; override;
procedure EssenceTo(MapElem: PMapElem); override;
end;
// get percent CPU Total
function getPercCT(var UpdateTime,CreationTime,ProcessTime:TFileTime):single;
implementation
uses
JwaWinNT,
JwaPsApi,
nCommon;
function FirstModuleName(hProcess: THandle):AnsiString;
var
cbNeeded: DWORD;
hModule: DWORD;
FileName:array[0..MAX_PATH] of Char;
begin
result:='';
if not EnumProcessModules(hProcess, @hModule, sizeof(DWORD), cbNeeded) then exit;
if cbNeeded=0 then exit;
GetModuleFileNameEx(hProcess, hModule, FileName, MAX_PATH);
result:=FileName;
end;
function KillProcessByName(appname:UnicodeString):Boolean;//true if kill or not found
var
isPsAPI,isTlHelp32: Boolean;
KernelHandle: THandle;
Snap: THandle;
PE: TProcessEntry32;
lpidProcess: PDWORD;
cb,cbNeeded:DWORD;
i:integer;
hProcess: THandle;
Str: UnicodeString;
begin
result:=false;
isPsAPI:=LoadLibrary('PSAPI.dll')<>0;
KernelHandle := GetModuleHandle('kernel32.dll');
if KernelHandle<>0 then
isTlHelp32:=GetProcAddress(KernelHandle, 'CreateToolhelp32Snapshot')<>nil
else isTlHelp32:=false;
if not isPsAPI and not isTlHelp32 then exit;
if isTlHelp32 then
begin
Snap := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if Snap = INVALID_HANDLE_VALUE then exit;
try
PE.dwSize := SizeOf(PE);
if Process32First(Snap, PE) then
repeat
if SameFileName(ExtractFileName(pe.szExeFile),'regedit.exe')
then KillSoftly(pe.th32ProcessID);
until not Process32Next(Snap, PE);
finally
CloseHandle(Snap);
result:=true;
end;
end
else if isPsAPI then
begin
cb := 32*4;
lpidProcess:=nil;
repeat //start from room to 64 processes
cb:=cb*2;
ReallocMem(lpidProcess,cb);
cbNeeded:=0;
if not EnumProcesses( pointer(lpidProcess), cb, cbNeeded ) then
begin
FreeMem(lpidProcess);
exit;
end;
until cbNeeded<cb;
for i:=0 to cbNeeded div 4 - 1 do
begin
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, lpidProcess[i]);
if hProcess<>0 then
begin
Str:=FirstModuleName(hProcess);
CloseHandle(hProcess);
if WideCompareFileName(ExtractFileName(Str),appname)=0
then KillSoftly(lpidProcess[i]);
end;
end;
FreeMem(lpidProcess);
end;
end;
procedure modules_list_PsAPI(modlist:TList; id: DWORD);
var
hProcess: THandle;
cb,cbNeeded:DWORD;
lpidModules: ^THandle;
FileName:array[0..MAX_PATH] of char;
i:integer;
moduleInfo: _MODULEINFO;
PMI: PModInfo;
begin
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, id);
if hProcess=0 then exit;
lpidModules:=nil;
cb := 16*4;
repeat //start from room to 32 modules
cb:=cb*2;
ReallocMem(lpidModules,cb);
cbNeeded:=0;
if not EnumProcessModules(hProcess, pointer(lpidModules), cb, cbNeeded ) then
begin
FreeMem(lpidModules);
exit;
end;
until cbNeeded<cb;
for i:=0 to cbNeeded div 4 - 1 do
begin
GetModuleFileNameEx(hProcess, lpidModules[i], FileName, MAX_PATH);
GetModuleInformation(hProcess, lpidModules[i], {$ifndef FPC}@{$endif}moduleInfo, sizeof(moduleInfo));
new(PMI);
PMI^.N:=i;
PMI^.Name:=ExtractFileName(FileName);
PMI^.Dir:=ExtractFilePath(FileName);
PMI^.Size:=moduleInfo.SizeOfImage;
PMI^.Base:=moduleInfo.lpBaseOfDll;
PMI^.Entry:=moduleInfo.EntryPoint;
modlist.Add(PMI);
end;
FreeMem(lpidModules);
CloseHandle(hProcess);
end;
procedure modules_list_TH32(modlist:TList; id: DWORD);
var
Snap: THandle;
ME: TModuleEntry32;
PMI: PModInfo;
begin
if id=0 then exit;
Snap := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE, id);
if Snap = INVALID_HANDLE_VALUE then exit;
try
ME.dwSize := SizeOf(ME);
if Module32First(Snap, ME) then
repeat
new(PMI);
PMI^.name:=ExtractFileName(ME.szExePath);
PMI^.dir:=ExtractFilePath(ME.szExePath);
PMI^.size:=ME.modBaseSize;
PMI^.Base:=ME.modBaseAddr;
PMI^.Entry:=nil;
modlist.Add(PMI);
until not Module32Next(Snap, ME);
finally
CloseHandle(Snap);
end;
end;
destructor TProcessInfo.Destroy;
begin
name1:='';
dir:='';
inherited;
end;
procedure TProcessInfo.EssenceTo(MapElem: PMapElem);
begin
MapElem^.id:=processID;
MapElem^.ProcessTime:=ProcessTime;
end;
function getPercCT(var UpdateTime,CreationTime,ProcessTime:TFileTime):single;
begin
if int64(CreationTime)=0 then
result:=0
else if int64(UpdateTime)+10000000<=int64(CreationTime) then
// clock set back after running process
result:=-1
else if int64(UpdateTime)<=int64(CreationTime) then
// process run after UpdateTime
result:=1
else
result:=int64(ProcessTime)/
(int64(UpdateTime)-int64(CreationTime));
end;
function MapCompare(Item1, Item2: Pointer): Integer;
var
id1,id2:DWORD;
begin
id1:=PMapElem(Item1)^.id;
id2:=PMapElem(Item2)^.id;
if id1<id2 then result:=-1
else if id1>id2 then result:=1
else result:=0;
end;
function TIntervStruct.GetCount: integer;
begin
result:=InfoList.Count;
end;
function TIntervStruct.GetInterval:TFileTime;
begin
int64(result):=int64(UpdateTime)-int64(PrevTime);
end;
constructor TIntervStruct.Create;
begin
InfoList:=TList.Create;
Map:=TList.Create;
end;
destructor TIntervStruct.Destroy;
begin
FreeMap;
Map.Free;
Clear;
InfoList.Free;
inherited;
end;
procedure TIntervStruct.Clear;
var
i:integer;
PPI: TCommInfo;
begin
for i:=0 to InfoList.Count-1 do
begin
PPI:=TObject(InfoList[i]) as TCommInfo;
PPI.Free;
end;
InfoList.Clear;
end;
{
If ProcList is filled and already used - we can make
map id to time;
}
procedure TIntervStruct.FreeMap;
var
i:integer;
MapElem: PMapElem;
begin
for i:=0 to Map.Count-1 do
begin
MapElem:=Map[i];
dispose(MapElem);
end;
Map.Clear;
end;
procedure TIntervStruct.MakeMap;
var
i:integer;
PPI: TCommInfo;
MapElem: PMapElem;
begin
FreeMap;
for i:=0 to InfoList.Count-1 do
begin
PPI:=TObject(InfoList[i]) as TCommInfo;
new(MapElem);
PPI.EssenceTo(MapElem);
Map.Add(MapElem);
end;
Map.Sort(@MapCompare);
PrevTime:=UpdateTime;
end;
function TIntervStruct.FindTime(id: DWORD; out time: FileTime):boolean;
var
pos,l,r:integer;
MapElem: PMapElem;
begin
l:=0; r:=Map.Count-1;
while(l<=r) do
begin
pos := (l+r) shr 1;
MapElem := Map[pos];
if MapElem^.id=id then
begin
time:=MapElem^.ProcessTime;
result:=true;
exit;
end else
if MapElem^.id>id then
r:=pos-1
else
l:=pos+1;
end;
result:=false;
end;
procedure TIntervStruct.SetupTime;
begin
GetSystemTimeAsFileTime(UpdateTime);
end;
procedure TThreadInfo.EssenceTo(MapElem: PMapElem);
begin
MapElem^.id:=id;
MapElem^.ProcessTime:=ProcessTime;
end;
procedure thread_list_TH32(var Threads: TIntervStruct; threadlist:TList; id: DWORD);
type
TOpenThread = function(dwDesiredAccess:DWORD; bInheritHandle:BOOL;
dwThreadId: DWORD):THandle;stdcall;
const
THREAD_QUERY_INFORMATION = $0040;
var
Snap: THandle;
T: TThreadEntry32;
TI: TThreadInfo;
hThread: THandle;
KernelHandle: THandle;
OpenThread: TOpenThread;
CreationTime, ExitTime, KernelTime, UserTime: TFileTime;
ThreadTimePrev: TFileTime;
begin
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
KernelHandle := GetModuleHandle('kernel32.dll');
if KernelHandle = 0 then exit;
OpenThread:=TOpenThread(GetProcAddress(KernelHandle, 'OpenThread'));//must load dynamically
if @OpenThread=nil then exit;
end else OpenThread:=nil;
Snap := CreateToolHelp32Snapshot(TH32CS_SNAPTHREAD, id);
if Snap = INVALID_HANDLE_VALUE then exit;
try
T.dwSize := SizeOf(T);
if Thread32First(Snap, T) then
repeat
if T.th32OwnerProcessID<>id then continue;
TI:=TThreadInfo.Create;
TI.BasePri:=T.tpBasePri;
TI.DeltaPri:=T.tpDeltaPri;
TI.id:=T.th32ThreadID;
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
hThread := OpenThread(THREAD_QUERY_INFORMATION, false, TI.id);
if hThread<>0 then
begin
GetThreadTimes(hThread,CreationTime,ExitTime,KernelTime,UserTime);
CloseHandle(hThread);
TI.CreationTime:=CreationTime;
TI.KernelTime:=KernelTime;
int64(TI.ProcessTime):=int64(KernelTime)+int64(UserTime);
TI.PercCpuTotal:=getPercCT(Threads.UpdateTime, TI.CreationTime,
TI.ProcessTime);
if Threads.FindTime(TI.Id,ThreadTimePrev) then
TI.PercCpu:=(int64(TI.ProcessTime)-int64(ThreadTimePrev))
/int64(Threads.Interval)
else TI.PercCpu:=TI.PercCpuTotal;
end;
end;
threadlist.Add(TI);
until not Thread32Next(Snap, T);
finally
CloseHandle(Snap);
end;
end;
end.