PPC的C/C++和人工智能学习笔记
每一篇学习笔记,都只是为了更好地掌握和理解

Win32SDK(14)_获取系统进程信息

今天学习:Windows的系统所有进程信息的获取

 

获取当前进程的HANDLE:GetCurrentProcess

HANDLE WINAPI GetCurrentProcess( VOID );

获得当前进程的一个伪句柄,该函数总是返回-1(0xFFFFFFFF)这个值。所以也可以用-1来替代。该函数获取的句柄不需要调用CloseHandle关闭,因为它是伪句柄。

 

获取当前进程的进程ID:GetCurrentProcessId

DWORD WINAPI GetCurrentProcessId( VOID );

 

根据进程ID获取进程HANDLE:OpenProcess

HANDLE WINAPI OpenProcess(

_In_ DWORD dwDesiredAccess,//访问权限,如PROCESS_ALL_ACCESS

_In_ BOOL bInheritHandle,//句柄是否继承,一般FALSE

_In_ DWORD dwProcessId);//进程ID

返回值:正确返回进程句柄,失败返回NULL。使用完需要用CloseHandle关闭句柄。

 

获取进程的路径1:GetModuleFileNameEx

<Psapi.h>,#pragma comment(lib,“Psapi.lib”)

DWORD WINAPI GetModuleFileNameEx(

_In_opt_ HANDLE hProcess, //目标进程的句柄,当前进程用(HANDLE)-1表示

_In_opt_ HMODULE hModule, //目标模块的句柄,NULL表示返回进程可执行文件的路径

_When_(return < nSize, _Out_writes_to_(nSize, return + 1))

_When_(return == nSize, _Out_writes_all_(nSize)) LPWSTR lpFilename,

//lpFilename是存放路径的字符串缓冲区

_In_ DWORD nSize); //nSize表示缓冲区的大小

返回值:函数调用失败将返回0,正确返回文件路径的字符串长度。注:进程的句柄须有PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限。

 

获取进程的路径2:GetProcessImageFileName

<Psapi.h>,#pragma comment(lib,“Psapi.lib”)

DWORD WINAPI GetProcessImageFileName (

_In_ HANDLE hProcess, //目标进程的句柄

_Out_writes_(nSize) LPWSTR lpImageFileName, //存放路径的字符串缓冲区

_In_ DWORD nSize ); //缓冲区大小

返回值:函数调用失败将返回0,正确返回文件路径的字符串长度。注:进程句柄需要有PROCESS_QUERY_INFORMATION的权限。

注意:使用此函数返回的路径不是通常的系统盘符,如”C:\…”,而是驱动层的表示方式”\Device\HarddiskVolume1\…”,所以使用起来不是很方便。

 

获取进程的路径3:QueryFullProcessImageName

BOOL WINAPI QueryFullProcessImageName(

_In_ HANDLE hProcess, //目标进程的句柄

_In_ DWORD dwFlags,//一般设为0(表示返回的路径是Win32的路径格式,如”C:\…”,如将其设为PROCESS_NAME_NATIVE将返回”\Device\HarddiskVolume1\…”这样的格式路径)

_Out_writes_to_(*lpdwSize, *lpdwSize) LPWSTR lpExeName, //字符串缓冲区

_Inout_ PDWORD lpdwSize); //缓冲区大小

返回值:函数失败将返回FALSE,正确返回TRUE。注:调用此函数的句柄须有PROCESS_QUERY_INFORMATION或这是PROCESS_QUERY_LIMITED_INFORMATION的权限,并且只能在Vista或更高版本的系统中使用。

 

获取所有系统进程ID:EnumProcesses 

<Psapi.h>,#pragma comment(lib,“Psapi.lib”)

BOOL WINAPI EnumProcesses (

_Out_writes_bytes_(cb) DWORD * lpidProcess, //进程ID数组

_In_ DWORD cb, //进程ID数组的字节数,sizeof(xxx)

_Out_ LPDWORD lpcbNeeded ); //DWORD指针,该指针指向的值除以sizeof(DWORD)就是总进程数量

 

练习:使用EnumProcesses,OpenProcess,GetModuleFileNameEx获取所有进程的ID, HANDLE, PATH。注意,此方法使用时会发现有很多的进程是无法OpenProcess和GetModuleFileNameEx的。

void onCreate(HWND hWnd) {
 //动态创建ListBox显示内容
 HWND hList = CreateWindow(_T("listbox"), NULL,
 WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL |WS_HSCROLL,
 1, 1, 985, 760, hWnd, HMENU(1001), g_hInst, NULL);
 //使用EnumProcesses,OpenProcess,GetModuleFileNameEx获取进程ID,HANDLE,PATH
 HANDLE h;
 DWORD procs[2048] = { 0 };
 DWORD need;
 TCHAR name[MAX_PATH + 1] = { 0 };
 TCHAR show[2048] = { 0 };
 int res = 0;
 EnumProcesses(procs, sizeof(procs), &need);
 need /= sizeof(DWORD); //总进程数量
 std::cout << "need=" << need << endl;
 for (int i = 0; i < need; ++i) {
 h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procs[i]);
 if (!h) {
 wsprintf(show, _T("ID:%d, OpenProcess Error!"), procs[i]);
 SendMessage(hList, LB_ADDSTRING, 0, LPARAM(show));
 }
 else {
 memset((LPVOID)name, 0, sizeof(name));
 res = GetModuleFileNameEx(h, NULL, name, MAX_PATH + 1);
 if (!res) {
 wsprintf(show, _T("ID:%d, GetModuleFileNameEx Error!"), procs[i]);
 SendMessage(hList, LB_ADDSTRING, 0, LPARAM(show));
 }
 else {
 wsprintf(show,_T("ID=%d,Path=%s"), procs[i], name);
 SendMessage(hList, LB_ADDSTRING, 0, LPARAM(show));
 }
 }
 }
}

 

获取系统进程快照:CreateToolhelp32Snapshot

#include <tlhelp32.h>

HANDLE WINAPI CreateToolhelp32Snapshot(

DWORD dwFlags,//用来指定快照中需要返回的对象,如TH32CS_SNAPPROCESS

DWORD th32ProcessID);//一个进程ID号,用来指定要获取哪一个进程的快照,如需要获取系统所有进程列表或获取当前进程快照时可以设为0

CreateToolhelp32Snapshot函数通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD]建立一个快照[snapshot]。

参数:dwFlags,指定快照中包含的系统内容,这个参数能够使用下列数值(常量)中的一个或多个。

TH32CS_INHERIT (0x80000000)- 声明快照句柄是可继承的。

TH32CS_SNAPALL – 在快照中包含系统中所有的进程和线程。

TH32CS_SNAPHEAPLIST(0x1):在快照中包含在th32ProcessID中指定的进程的所有的堆。

TH32CS_SNAPMODULE(0x8):在快照中包含在th32ProcessID中指定的进程的所有的模块。

TH32CS_SNAPPROCESS(0x2):在快照中包含系统中所有的进程

TH32CS_SNAPTHREAD(0x4):在快照中包含系统中所有的线程。

TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD  |  TH32CS_SNAPMODULE)

参数:th32ProcessID,指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,所有的进程都会被快照

返回值:调用成功,返回快照的句柄,调用失败,返回INVALID_HANDLE_VALUE 。

注意:需要使用CloseHandle关闭快照句柄。

 

存放快照进程信息的结构体,PROCESSENTRY32:

typedef struct tagPROCESSENTRY32{

DWORD   dwSize; //结构体大小

DWORD   cntUsage; //此进程的引用计数,不再使用,总为0

DWORD   th32ProcessID;          // 该进程的ID

ULONG_PTR th32DefaultHeapID; //进程默认堆,不再使用,总为0

DWORD   th32ModuleID;         //进程模块ID,不再使用,总为0

DWORD   cntThreads;           //进程开启的线程计数

DWORD   th32ParentProcessID;  //父进程的ID

LONG    pcPriClassBase; //线程优先权,当前进程创建的任何一个线程的基础优先级

DWORD   dwFlags;        //不再使用,总为0

WCHAR   szExeFile[MAX_PATH]; //进程的可执行文件名称。要获得可执行文件的完整路径,应调用Module32First函数,再检查其返回的MODULEENTRY32结构的szExePath成员。但是,如果被调用进程是一个64位程序,您必须调用QueryFullProcessImageName函数去获取64位进程的可执行文件完整路径名。

} PROCESSENTRY32;

 

存放快照模块信息的结构体,MODULEENTRY32:

typedef struct tagMODULEENTRY32{

DWORD   dwSize; //结构体长度

DWORD   th32ModuleID;      //不再使用,通常置为1

DWORD   th32ProcessID;     //进程ID

DWORD   GlblcntUsage; //全局模块的使用计数,即模块的总载入次数。通常这一项是没有意义的,被设置为0xFFFF。

DWORD   ProccntUsage; //全局模块的使用计数(与GlblcntUsage相同)。通常这一项也是没有意义的,被设置为0xFFFF。

BYTE  * modBaseAddr;    //模块的基址,在其所属的进程范围内

DWORD   modBaseSize;    //模块的大小,单位字节。

HMODULE hModule;        //所属进程的范围内,模块句柄。

WCHAR   szModule[MAX_MODULE_NAME32 + 1]; //模块名

WCHAR   szExePath[MAX_PATH]; //模块路径

} MODULEENTRY32;

 

获取快照第一个进程的信息,Process32First

BOOL WINAPI Process32First(

HANDLE hSnapshot, //快照句柄

LPPROCESSENTRY32 lppe); //PROCESSENTRY32结构体,用来保存输出信息

返回值:成功返回TRUE,失败返回FALSE

 

获取快照下一个进程的信息,Process32Next

BOOL WINAPI Process32Next(

HANDLE hSnapshot, //快照句柄

LPPROCESSENTRY32 lppe); //PROCESSENTRY32结构体,用来保存输出信息

返回值:成功返回TRUE,失败返回FALSE

 

获取快照第一个模块的信息,Module32First

BOOL WINAPI Module32First(

HANDLE hSnapshot, //快照句柄

LPMODULEENTRY32W lpme); //存放模块信息的结构体指针

返回值:成功返回TRUE,失败返回FALSE

 

获取快照下一个模块的信息,Module32Next

BOOL WINAPI Module32Next(

HANDLE hSnapshot, //快照句柄

LPMODULEENTRY32W lpme); //存放模块信息的结构体指针

返回值:成功返回TRUE,失败返回FALSE

练习,使用快照列举所有的进程ID和路径。同样会发现问题,很多进程无法获取路径。

void onCreate2(HWND hWnd) {
 //动态创建ListBox显示内容
 HWND hList = CreateWindow(_T("listbox"), NULL,
 WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL,
 900, 1, 885, 760, hWnd, HMENU(1002), g_hInst, NULL);
 //使用快照遍历所有进程
 TCHAR show[2048] = { 0 };
 HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 if (hSnap == INVALID_HANDLE_VALUE) { //快照失败
 wprintf(show, _T("CreateToolhelp32Snapshot Error!"));
 SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)show);
 }
 else {
 cout << "SNAP OK" << endl;
 PROCESSENTRY32 pe = { 0 };
 pe.dwSize = sizeof(PROCESSENTRY32);
 BOOL haveNext = Process32First(hSnap, &pe);
 while (haveNext) {
 //memset((LPVOID)show, 0, sizeof(show));
 //通过模块快照,获取全路径
 TCHAR pathName[MAX_PATH + 1] = { 0 };
 HANDLE hModule = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe.th32ProcessID);
 if (hModule == INVALID_HANDLE_VALUE || pe.th32ProcessID==0) {//创建模块快照失败 
 //进程id=0会默认为是当前进程,所以不处理,实际上是[System Process]
 _tcscpy_s(pathName, pe.szExeFile);
 _tcscat_s(pathName, _T("模块快照失败。"));
 }
 else { //模块快照成功
 MODULEENTRY32 me = { 0 };
 me.dwSize = sizeof(MODULEENTRY32);
 if (!Module32First(hModule, &me)) {
 _tcscpy_s(pathName, pe.szExeFile);
 _tcscat_s(pathName, _T("模块快照成功,ModuleFirst32失败。"));
 }
 else {
 _tcscpy_s(pathName, me.szExePath);
 }
 }
 CloseHandle(hModule); //关闭模块快照

 wsprintf(show, _T("ID=%d,Path=%s"), pe.th32ProcessID, pathName);
 SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)show);
 haveNext = Process32Next(hSnap, &pe);
 }
 }
 CloseHandle(hSnap);
}

 

 

 

 

(2017-06-18 www.vsppc.com)

学习笔记未经允许不得转载:PPC的C/C++和人工智能学习笔记 » Win32SDK(14)_获取系统进程信息

分享到:更多 ()

评论 抢沙发

评论前必须登录!