一、函數介紹
在Windows系統中動態鏈接庫kernel32.dll提供了獲取和處理系統進程的許多接口函數,Delphi語言把這些函數接口封裝到Tlhelp32.pas中,供Delphi用戶開發過程調用。要詳細了解相關知識可以查閱Tlhelp32.pas原文件和Windows SDK提供的幫助文件。其中同本文涉及的接口函數主要有CreateToolhelp32Snapshot、process32first、 process32next、module32first、module32next五個函數以及TMODULEENTRY32、 TPROCESSENTRY32兩個數據結構。
1、CreateToolhelp32Snapshot
該函數是要實現上述目的最核心的一個函數,它可以獲取系統運行進程(Process)列表、線程(Thread)列表和指定運行進程的堆 (Heap)列表、調用模塊(Module)列表。
如果函數運行成功將返回一個非零"Snapshot"句柄,通過該句柄調用相關WinAPI函數就可以實現上述目的,其函數格式為:
HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID);
參數說明:
snapshot:"快照"
dwFlags參數:對函數建立的"Snapshot"所包含的列表類型,可選項包括:
TH32CS_SNAPHEAPLIST:所創建的Snapshot包含堆列表
TH32CS_SNAPMODULE :所創建的Snapshot包含調用模塊列表
TH32CS_SNAPTHREAD :所創建的Snapshot包含線程列表;
TH32CS_SNAPPROCESS :所創建的Snapshot包含進程列表;
TH32CS_SNAPALL :所創建的Snapshot包含上述所有列表;
th32ProcessID參數:
進程句柄參數,可以為零表示當前進程,該參數只對dwFlags包含TH32CS_SNAPMODULE、
TH32CS_SNAPHEAPLIST可選項時起作用。
當dwFlags為TH32CS_SNAPPROCESS,
th32ProcessID為零時函數得到系統的所有進程列表。
2、Process32First、Process32Next、Module32First、Module32Next
這四個函數都是對"Snapshot"所包含的列表進行息獲取,根據函數字面的英文意義,不難理解各函數的含義和區別,四個函數的格式分別為:
BOOL WINAPI Process32First(HANDLE hSnapshot,
LPPROCESSENTRY32 lppe);
BOOL WINAPI Process32Next(HANDLE hSnapshot,
LPPROCESSENTRY32 lppe);
BOOL WINAPI Module32First(HANDLE hSnapshot,
LPMODULEENTRY32 lpme);
BOOL WINAPI Module32Next(HANDLE hSnapshot,
LPMODULEENTRY32 lpme);
3、TMODULEENTRY32、TPROCESSENTRY32
這兩個數據結構中TPROCESSENTRY32是在Process32First、Process32Next兩個函數所用到的數據結構,TMODULEENTRY32是在Module32First、Module32Next所用到的數據結構,兩個數據結構分別如下:
typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID; //進程句柄
DWORD th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
char szExeFile[MAX_PATH];
} PROCESSENTRY32;
typedef struct tagMODULEENTRY32 {
DWORD dwSize;
DWORD th32ModuleID;
DWORD th32ProcessID;
DWORD GlblcntUsage;
DWORD ProccntUsage;
BYTE * modBaseAddr;
DWORD modBaseSize;
HMODULE hModule;
char szModule[MAX_MODULE_NAME32 + 1];
char szExePath[MAX_PATH]; //調用模塊的含路徑文件名www.2cto.com
} MODULEENTRY32;
在使用上面兩個數據結構要特別強調一點,那就是函數使用這兩個數據結構的變量時要先設置dwSize的值,分別用sizeof(TPROCESSENTRY32)和sizeof(TMODULEENTRY32)。
由於篇幅有限以上所提到的函數和數據結構可以查看Windows SDK幫助文件獲取更詳細的信息。
二、實現原理
要實現獲得系統的所有運行進程和每個運行進程所調用模塊的信息,實際上只要使用兩重循環,外循環獲取系統的所有進程列表,內循環獲取每個進程所調用模塊列表。用以下四組API調用實現:
1、創建系統的所有進程列表
ProcessList:= CreateToolhelp32Snapshot
(TH32CS_SNAPPROCESS,0);
2、提取進程列表項信息存儲在TPROCESSENTRY32 pe32中
Process32First(ProcessList,pe)
Process32Next(ProcessList,pe)
3、創建指定進程所有調用模塊列表
ModuleRec:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
pe.processID);
4、提取調用模塊列表項信息存儲在TMODULEENTRY32 pm中
Module32First(ModuleList,pm);
Module32Next(ModuleList,pm);
三、核心源碼
有了以上知識以後,我們就可以很容易地實現獲取系統的所有進程以及各進程運行過程所調用的模塊文件了。
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,Messages,Windows,Tlhelp32;
var
processRec: Thandle;
pe32: TProcessEntry32;
processNum: Integer;
procedure EnumModule(processid: DWORD);
var
moduleRec: THandle;
pm: TModuleEntry32;
begin
// create module snapshot
moduleRec := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,processID);
//module size
pm.dwSize := sizeof(TModuleEntry32);
// first module?
if ( module32First(moduleRec,pm) ) then
begin
while Module32Next(moduleRec,pm) do
begin
Writeln('module name: ',StrPas(pm.szModule));
end;
end;
CloseHandle(moduleRec);
end;
procedure OutProcessName(processName: string);
begin
WriteLn('Process Name:',processName);
end;
begin
processNum := 0;
//create process snapshot
processRec := CreateToolHelp32Snapshot( TH32CS_SNAPPROCESS,0 );
pe32.dwSize := sizeOf( TPROCESSENTRY32 );
if Process32First( processRec, pe32) then
begin
// enum the process module
OutProcessName( pe32.szExeFile );
EnumModule( pe32.th32ProcessID );
inc(processNum); //inc process count
while Process32Next( processRec,pe32 ) do
begin
OutProcessName( pe32.szExeFile );
EnumModule( pe32.th32ProcessID );
inc(processNum);//inc process count
end;
WriteLn('Total System Process:',processNum);
CloseHandle(processRec);
Readln;
end;
end.
摘自 TryHard