HOWTO:使用 Win32 API 枚举应用程序

一个常见的编程任务是枚举所有运行的"应用程序"。Windows 任务管理器就是一个很好的例子。它用两种方式列出"应用程序"。任务管理器的第一个选项卡列出桌面上的所有"应用程序窗口"。第二个选项卡列出系统中的所有"进程"。本文提供了如何执行这些任务的详细信息。

更多信息

枚举顶层窗口

如果将枚举进程与枚举桌面上的顶层窗口进行比较,那么枚举顶层窗口可能更容易一些。要枚举顶层窗口,请使用 EnumWindows() 函数。不要使用 GetWindow() 创建自己的窗口列表,因为它可能受 z 轴次序更改和丢失窗口的干扰。

EnumWindows() 将指向某个回调函数的指针以及用户定义的 LPARAM 值作为其参数。它对桌面上的每个窗口(或顶层窗口)分别调用一次回调函数。然后,回调函数可以对此窗口句柄进行某种处理,如将其添加到一个列表中。此方法可以保证不受窗口 z 轴次序更改等项的干扰。在获取窗口句柄后,可以通过调用 GetWindowText() 来获取其标题。

枚举进程

在系统中创建进程列表比枚举窗口要稍微复杂一些。这主要是因为执行此操作的 API 函数因所使用的 Win32 操作系统而异。在 Windows 95、Windows 98、Windows Millennium Edition、Windows 2000 和 Windows XP 中,可以使用 ToolHelp32 API 库中的函数。但是,在 Windows NT 中,必须使用 PSAPI API 库中的函数(Platform SDK 中包含该库)。本文将讨论这两种技术,另外还提供一个称为 EnumProcs() 的示例包装函数,该函数可以在 Win32 操作系统中运行。

使用 ToolHelp32 库枚举进程

首先讨论 ToolHelp32 方法。KERNEL32.dll 中的 ToolHelp32 函数是标准的 API 函数。注意,在 Windows NT 4.0 中不提供这些 API。

可以使用 ToolHelp32 提供的各种函数,枚举系统中的进程和线程以及获取内存和模块信息。但是,在枚举进程时,仅需要使用以下三个函数:CreateToolhelp32Snapshot()Process32First()  Process32Next()

使用 ToolHelp32 函数的第一步是创建系统信息的"快照"。可以使用 CreateToolhelp32Snapshot() 函数完成这一步。此函数允许选择在快照中存储的信息类型。如果您需要进程信息,则一定要包括 TH32CS_SNAPPROCESS 标志。CreateToolhelp32Snapshot() 函数返回一个句柄,在使用完该句柄后,必须将其传递到CloseHandle()

下一步,为了检索快照中的进程列表,可以调用一次 Process32First,然后重复调用多次 Process32Next。执行此操作,直到其中的一个函数返回 FALSE 为止。这将逐个获得快照进程列表中的进程。这两个函数都将"快照"句柄和指向 PROCESSENTRY32 结构的指针作为其参数。

在调用 Process32First  Process32Next 后,PROCESSENTRY32 结构将包含系统中某个进程的有用信息。进程 ID 在该结构的 th32ProcessID 成员中。可以将它传递到 OpenProcess() 以获取该进程的句柄。该进程的可执行文件和路径存储在结构的 szExeFile 成员中。还可以在此结构中找到其他有用的信息。

备注:切记,在调用 Process32First() 之前,将 PROCESSENTRY32 结构的 dwSize 成员设置为 sizeof(PROCESSENTRY32)

使用 PSAPI 库枚举进程

在 Windows NT 中创建进程列表的方法是使用 PSAPI.dll 中的 PSAPI 函数。此文件是随 Platform SDK 分发的,可以从以下 Microsoft Web 站点下载该文件:
Microsoft Platform SDK 
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ (http://www.microsoft.com/msdownload/platformsdk/sdkupdate/)
所需的 PSAPI.h 和 PSAPI.lib 文件也包含在 Platform SDK 中。

要使用 PSAPI 库中的函数,请将 PSAPI.lib 文件添加到您的项目中,并将 PSAPI.h 文件包含到任何调用 PSAPI API 的模块中。切记,要将 PSAPI.dll 文件与使用它的任何可执行文件一起分发,因为没有随 Windows NT 4.0 分发该文件。可以从以下位置下载可重新分发的 PSAPI.dll 版本(如果没有完整的 Platform SDK 的话):
Platform SDK 可重新分发的版本:用于 Windows NT 的 PSAPI
http://www.microsoft.com/downloads/release.asp?releaseid=30337 (http://www.microsoft.com/downloads/release.asp?releaseid=3 0337)
与 ToolHelp32 函数一样,PSAPI 也包含很多其他的有用函数。但是,本文只讨论与枚举进程有关的函数:EnumProcesses()EnumProcessModules()GetModuleFileNameEx()  GetModuleBaseName()

创建进程列表的第一步是调用 EnumProcesses()。以下是其声明:
HOWTO:使用 Win32 API 枚举应用程序BOOL EnumProcesses( DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded );
需要给 EnumProcesses() 传入三个参数:指向 DWORD 数组的指针 (lpidProcess)、该数组的大小 (cb) 以及另一个指向 DWORD 的指针 (cbNeeded)(用于获取返回数据的长度)。使用当前所运行进程的进程 ID 数组来填充 DWORD 数组。cbNeeded 参数返回所使用数组的大小。以下计算告诉您返回了多少个进程 ID:nReturned = cbNeeded / sizeof(DWORD)。

备注:虽然本文将返回的 DWORD 命名为"cbNeeded",但实际上无法确定在数组中传递的进程到底有多少。EnumProcesses()  cbNeeded 中返回的值绝不会大于在 cb 参数中传递的数组值。因此,要确保成功使用 EnumProcesses() 函数,唯一的方法是分配一个 DWORD 数组,如果返回时 cbNeeded 等于 cb,则分配较大的数组并重试,直到 cbNeeded 小于 cb 时为止。

现在,数组包含系统中的每个进程 ID。如果您的目标是获取进程名,则必须先获取句柄。要从进程 ID 中获取句柄,请使用 OpenProcess()

在获取句柄后,需要获取进程的第一个模块。要获取进程的第一个模块,请使用以下参数调用 EnumProcessModules() API: 
HOWTO:使用 Win32 API 枚举应用程序EnumProcessModules( hProcess, &hModule, sizeof(hModule), &cbReturned );
这将把进程第一个模块的句柄放在 hModule 变量中。切记,进程实际上并没有名称,但进程中的第一个模块是该进程的可执行文件。现在,可以将返回的模块句柄 (hModule) 用于 GetModuleFileNameEx()  GetModuleBaseName() API,以获取进程可执行文件的完整路径名或简单模块名。这两个函数需要传入进程句柄、模块句柄以及返回名称的缓冲区指针,后面是缓冲区的大小。

通过对 EnumProcesses() API 返回的每个进程 ID 重复上述步骤,即可创建 Windows NT 中进程的列表。

16 位进程

在 Windows 95、Windows 98 和 Windows Millennium Edition 上,对 ToolHelp32 而言,所有 16 位应用程序是平等的。与 Win32 应用程序一样,16 位应用程序也具有进程 ID 等。但是,在 Windows NT、Windows 2000 或 Windows XP 中,则不是这样。在这些操作系统上,16 位应用程序运行在 DOS 虚拟机 (VDM) 中。

要在 Windows NT、Windows 2000 和 Windows XP 中枚举 16 位应用程序,必须使用名为 VDMEnumTaskWOWEx() 的函数。必须在源模块中包含 VDMDBG.h,并且 VDMDBG.lib 文件必须与项目链接在一起。这两个文件包含在 Platform SDK 中。

此函数的声明如下: 
HOWTO:使用 Win32 API 枚举应用程序INT WINAPI VDMEnumTaskWOWEx( DWORD dwProcessId, TASKENUMPROCEX fp,
HOWTO:使用 Win32 API 枚举应用程序LPARAM lparam );
其中,dwProcessId 是要枚举其 16 位任务的 NTVDM 进程的标识符。fp 参数是指向回调枚举函数的指针。lparam 参数是要传递给枚举函数的用户定义值。

枚举函数应当定义如下: 
HOWTO:使用 Win32 API 枚举应用程序BOOL WINAPI Enum16( DWORD dwThreadId, WORD hMod16, WORD hTask16, PSZ
HOWTO:使用 Win32 API 枚举应用程序pszModName, PSZ pszFileName, LPARAM lpUserDefined );
对于传递到 VDMEnumTaskWOWEx() 的 NTVDM 进程中运行的每个 16 位任务,分别调用一次该函数。如果要继续枚举,则应该返回 FALSE,如果要结束枚举,则应该返回 TRUE。注意,这与 EnumWindows() 正好相反。

示例代码

下示例代码将 PSAPI 和 ToolHelp32 函数封装在名为 EnumProcs() 的函数中。此函数与 EnumWindows() 类似,因为它也接受指向某个函数的指针并重复调用它(对系统中的每个进程分别调用一次)。以下是该函数的声明: 
HOWTO:使用 Win32 API 枚举应用程序BOOL WINAPI EnumProcs( PROCENUMPROC lpProc, LPARAM lParam );
如果使用该函数,则将回调函数声明如下:
HOWTO:使用 Win32 API 枚举应用程序BOOL CALLBACK Proc( DWORD dw, WORD w16, LPCSTR lpstr, LPARAM lParam );
其中,dw 参数将包含 ID;"w16"是 16 位任务编号或 0(如果是 32 位进程,则在 Windows 95 下始终为零);lpstr 参数将指向文件名;lParam 是传递给 EnumProcs() 的用户定义的 lParam

EnumProcs() 函数通过显式链接使用 ToolHelp32 和 PSAPI 函数,而不是通过更常用的隐式链接。通过使用这种技术,可以使代码在所有 Win32 操作系统中二进制兼容。
HOWTO:使用 Win32 API 枚举应用程序//
HOWTO:使用 Win32 API 枚举应用程序
// EnumProc.c
HOWTO:使用 Win32 API 枚举应用程序
//
HOWTO:使用 Win32 API 枚举应用程序
#include <windows.h>
HOWTO:使用 Win32 API 枚举应用程序#include <stdio.h>
HOWTO:使用 Win32 API 枚举应用程序#include <tlhelp32.h>
HOWTO:使用 Win32 API 枚举应用程序#include <vdmdbg.h>
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序typedef struct {
HOWTO:使用 Win32 API 枚举应用程序DWORD          dwPID;
HOWTO:使用 Win32 API 枚举应用程序PROCENUMPROC   lpProc;
HOWTO:使用 Win32 API 枚举应用程序DWORD          lParam;
HOWTO:使用 Win32 API 枚举应用程序BOOL           bEnd;
HOWTO:使用 Win32 API 枚举应用程序}
 EnumInfoStruct;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
HOWTO:使用 Win32 API 枚举应用程序PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序//
HOWTO:使用 Win32 API 枚举应用程序
// The EnumProcs function takes a pointer to a callback function
HOWTO:使用 Win32 API 枚举应用程序
// that will be called once per process with the process filename
HOWTO:使用 Win32 API 枚举应用程序
// and process ID.
HOWTO:使用 Win32 API 枚举应用程序
//
HOWTO:使用 Win32 API 枚举应用程序
// lpProc -- Address of callback routine.
HOWTO:使用 Win32 API 枚举应用程序
//
HOWTO:使用 Win32 API 枚举应用程序
// lParam -- A user-defined LPARAM value to be passed to
HOWTO:使用 Win32 API 枚举应用程序
//           the callback routine.
HOWTO:使用 Win32 API 枚举应用程序
//
HOWTO:使用 Win32 API 枚举应用程序
// Callback function definition:
HOWTO:使用 Win32 API 枚举应用程序
// BOOL CALLBACK Proc(DWORD dw, WORD w, LPCSTR lpstr, LPARAM lParam);
HOWTO:使用 Win32 API 枚举应用程序
//
HOWTO:使用 Win32 API 枚举应用程序
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序OSVERSIONINFO  osver;
HOWTO:使用 Win32 API 枚举应用程序HINSTANCE      hInstLib  = NULL;
HOWTO:使用 Win32 API 枚举应用程序HINSTANCE      hInstLib2 = NULL;
HOWTO:使用 Win32 API 枚举应用程序HANDLE         hSnapShot = NULL;
HOWTO:使用 Win32 API 枚举应用程序LPDWORD        lpdwPIDs  = NULL;
HOWTO:使用 Win32 API 枚举应用程序PROCESSENTRY32 procentry;
HOWTO:使用 Win32 API 枚举应用程序BOOL           bFlag;
HOWTO:使用 Win32 API 枚举应用程序DWORD          dwSize;
HOWTO:使用 Win32 API 枚举应用程序DWORD          dwSize2;
HOWTO:使用 Win32 API 枚举应用程序DWORD          dwIndex;
HOWTO:使用 Win32 API 枚举应用程序HMODULE        hMod;
HOWTO:使用 Win32 API 枚举应用程序HANDLE         hProcess;
HOWTO:使用 Win32 API 枚举应用程序char           szFileName[MAX_PATH];
HOWTO:使用 Win32 API 枚举应用程序EnumInfoStruct sInfo;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// ToolHelp Function Pointers.
HOWTO:使用 Win32 API 枚举应用程序
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD);
HOWTO:使用 Win32 API 枚举应用程序BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32);
HOWTO:使用 Win32 API 枚举应用程序BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// PSAPI Function Pointers.
HOWTO:使用 Win32 API 枚举应用程序
BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *);
HOWTO:使用 Win32 API 枚举应用程序BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD,
HOWTO:使用 Win32 API 枚举应用程序LPDWORD);
HOWTO:使用 Win32 API 枚举应用程序DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// VDMDBG Function Pointers.
HOWTO:使用 Win32 API 枚举应用程序
INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Retrieve the OS version
HOWTO:使用 Win32 API 枚举应用程序
osver.dwOSVersionInfoSize = sizeof(osver);
HOWTO:使用 Win32 API 枚举应用程序if (!GetVersionEx(&osver))
HOWTO:使用 Win32 API 枚举应用程序return FALSE;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// If Windows NT 4.0
HOWTO:使用 Win32 API 枚举应用程序
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
HOWTO:使用 Win32 API 枚举应用程序&& osver.dwMajorVersion == 4) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序__try {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Get the procedure addresses explicitly.We do
HOWTO:使用 Win32 API 枚举应用程序
// this so we don't have to worry about modules
HOWTO:使用 Win32 API 枚举应用程序
// failing to load under OSes other than Windows NT 4.0
HOWTO:使用 Win32 API 枚举应用程序
// because references to PSAPI.DLL can't be resolved.
HOWTO:使用 Win32 API 枚举应用程序
hInstLib = LoadLibraryA("PSAPI.DLL");
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序hInstLib2 = LoadLibraryA("VDMDBG.DLL");
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib2 == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Get procedure addresses.
HOWTO:使用 Win32 API 枚举应用程序
lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*))
HOWTO:使用 Win32 API 枚举应用程序GetProcAddress(hInstLib, "EnumProcesses");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *,
HOWTO:使用 Win32 API 枚举应用程序DWORD, LPDWORD)) GetProcAddress(hInstLib,
HOWTO:使用 Win32 API 枚举应用程序"EnumProcessModules");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE,
HOWTO:使用 Win32 API 枚举应用程序LPTSTR, DWORD)) GetProcAddress(hInstLib,
HOWTO:使用 Win32 API 枚举应用程序"GetModuleBaseNameA");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
HOWTO:使用 Win32 API 枚举应用程序LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (lpfEnumProcesses == NULL
HOWTO:使用 Win32 API 枚举应用程序|| lpfEnumProcessModules == NULL
HOWTO:使用 Win32 API 枚举应用程序|| lpfGetModuleBaseName == NULL
HOWTO:使用 Win32 API 枚举应用程序|| lpfVDMEnumTaskWOWEx == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序         //
HOWTO:使用 Win32 API 枚举应用程序
// Call the PSAPI function EnumProcesses to get all of the
HOWTO:使用 Win32 API 枚举应用程序
// ProcID's currently in the system.
HOWTO:使用 Win32 API 枚举应用程序         
//
HOWTO:使用 Win32 API 枚举应用程序
// NOTE:In the documentation, the third parameter of
HOWTO:使用 Win32 API 枚举应用程序
// EnumProcesses is named cbNeeded, which implies that you
HOWTO:使用 Win32 API 枚举应用程序
// can call the function once to find out how much space to
HOWTO:使用 Win32 API 枚举应用程序
// allocate for a buffer and again to fill the buffer.
HOWTO:使用 Win32 API 枚举应用程序
// This is not the case.The cbNeeded parameter returns
HOWTO:使用 Win32 API 枚举应用程序
// the number of PIDs returned, so if your buffer size is
HOWTO:使用 Win32 API 枚举应用程序
// zero cbNeeded returns zero.
HOWTO:使用 Win32 API 枚举应用程序         
//
HOWTO:使用 Win32 API 枚举应用程序
// NOTE:The "HeapAlloc" loop here ensures that we
HOWTO:使用 Win32 API 枚举应用程序
// actually allocate a buffer large enough for all the
HOWTO:使用 Win32 API 枚举应用程序
// PIDs in the system.
HOWTO:使用 Win32 API 枚举应用程序         
//
HOWTO:使用 Win32 API 枚举应用程序
dwSize2 = 256 * sizeof(DWORD);
HOWTO:使用 Win32 API 枚举应用程序do {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (lpdwPIDs) {
HOWTO:使用 Win32 API 枚举应用程序HeapFree(GetProcessHeap(), 0, lpdwPIDs);
HOWTO:使用 Win32 API 枚举应用程序dwSize2 *= 2;
HOWTO:使用 Win32 API 枚举应用程序            }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序lpdwPIDs = (LPDWORD) HeapAlloc(GetProcessHeap(), 0,
HOWTO:使用 Win32 API 枚举应用程序dwSize2);
HOWTO:使用 Win32 API 枚举应用程序if (lpdwPIDs == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize))
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序}
 while (dwSize == dwSize2);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// How many ProcID's did we get?
HOWTO:使用 Win32 API 枚举应用程序
dwSize /= sizeof(DWORD);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Loop through each ProcID.
HOWTO:使用 Win32 API 枚举应用程序
for (dwIndex = 0; dwIndex < dwSize; dwIndex++) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序szFileName[0] = 0;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Open the process (if we canHOWTO:使用 Win32 API 枚举应用程序 security does not
HOWTO:使用 Win32 API 枚举应用程序
// permit every process in the system to be opened).
HOWTO:使用 Win32 API 枚举应用程序
hProcess = OpenProcess(
HOWTO:使用 Win32 API 枚举应用程序PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
HOWTO:使用 Win32 API 枚举应用程序FALSE, lpdwPIDs[dwIndex]);
HOWTO:使用 Win32 API 枚举应用程序if (hProcess != NULL) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Here we call EnumProcessModules to get only the
HOWTO:使用 Win32 API 枚举应用程序
// first module in the process.This will be the
HOWTO:使用 Win32 API 枚举应用程序
// EXE module for which we will retrieve the name.
HOWTO:使用 Win32 API 枚举应用程序
if (lpfEnumProcessModules(hProcess, &hMod,
HOWTO:使用 Win32 API 枚举应用程序sizeof(hMod), &dwSize2)) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Get the module name
HOWTO:使用 Win32 API 枚举应用程序
if (!lpfGetModuleBaseName(hProcess, hMod,
HOWTO:使用 Win32 API 枚举应用程序szFileName, sizeof(szFileName)))
HOWTO:使用 Win32 API 枚举应用程序szFileName[0] = 0;
HOWTO:使用 Win32 API 枚举应用程序               }

HOWTO:使用 Win32 API 枚举应用程序CloseHandle(hProcess);
HOWTO:使用 Win32 API 枚举应用程序            }

HOWTO:使用 Win32 API 枚举应用程序// Regardless of OpenProcess success or failure, we
HOWTO:使用 Win32 API 枚举应用程序
// still call the enum func with the ProcID.
HOWTO:使用 Win32 API 枚举应用程序
if (!lpProc(lpdwPIDs[dwIndex], 0, szFileName, lParam))
HOWTO:使用 Win32 API 枚举应用程序break;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Did we just bump into an NTVDM?
HOWTO:使用 Win32 API 枚举应用程序
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Fill in some info for the 16-bit enum proc.
HOWTO:使用 Win32 API 枚举应用程序
sInfo.dwPID = lpdwPIDs[dwIndex];
HOWTO:使用 Win32 API 枚举应用程序sInfo.lpProc = lpProc;
HOWTO:使用 Win32 API 枚举应用程序sInfo.lParam = (DWORD) lParam;
HOWTO:使用 Win32 API 枚举应用程序sInfo.bEnd = FALSE;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Enum the 16-bit stuff.
HOWTO:使用 Win32 API 枚举应用程序
lpfVDMEnumTaskWOWEx(lpdwPIDs[dwIndex],
HOWTO:使用 Win32 API 枚举应用程序(TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Did our main enum func say quit?
HOWTO:使用 Win32 API 枚举应用程序
if (sInfo.bEnd)
HOWTO:使用 Win32 API 枚举应用程序break;
HOWTO:使用 Win32 API 枚举应用程序            }

HOWTO:使用 Win32 API 枚举应用程序         }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序}
 __finally {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib)
HOWTO:使用 Win32 API 枚举应用程序FreeLibrary(hInstLib);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib2)
HOWTO:使用 Win32 API 枚举应用程序FreeLibrary(hInstLib2);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (lpdwPIDs)
HOWTO:使用 Win32 API 枚举应用程序HeapFree(GetProcessHeap(), 0, lpdwPIDs);
HOWTO:使用 Win32 API 枚举应用程序      }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// If any OS other than Windows NT 4.0.
HOWTO:使用 Win32 API 枚举应用程序
}
 else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
HOWTO:使用 Win32 API 枚举应用程序|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
HOWTO:使用 Win32 API 枚举应用程序&& osver.dwMajorVersion > 4)) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序__try {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序hInstLib = LoadLibraryA("Kernel32.DLL");
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// If NT-based OS, load VDMDBG.DLL.
HOWTO:使用 Win32 API 枚举应用程序
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
HOWTO:使用 Win32 API 枚举应用程序hInstLib2 = LoadLibraryA("VDMDBG.DLL");
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib2 == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序         }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Get procedure addresses.We are linking to
HOWTO:使用 Win32 API 枚举应用程序
// these functions explicitly, because a module using
HOWTO:使用 Win32 API 枚举应用程序
// this code would fail to load under Windows NT,
HOWTO:使用 Win32 API 枚举应用程序
// which does not have the Toolhelp32
HOWTO:使用 Win32 API 枚举应用程序
// functions in KERNEL32.DLL.
HOWTO:使用 Win32 API 枚举应用程序
lpfCreateToolhelp32Snapshot =
HOWTO:使用 Win32 API 枚举应用程序(HANDLE (WINAPI *)(DWORD,DWORD))
HOWTO:使用 Win32 API 枚举应用程序GetProcAddress(hInstLib, "CreateToolhelp32Snapshot");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序lpfProcess32First =
HOWTO:使用 Win32 API 枚举应用程序(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
HOWTO:使用 Win32 API 枚举应用程序GetProcAddress(hInstLib, "Process32First");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序lpfProcess32Next =
HOWTO:使用 Win32 API 枚举应用程序(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
HOWTO:使用 Win32 API 枚举应用程序GetProcAddress(hInstLib, "Process32Next");
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (lpfProcess32Next == NULL
HOWTO:使用 Win32 API 枚举应用程序|| lpfProcess32First == NULL
HOWTO:使用 Win32 API 枚举应用程序|| lpfCreateToolhelp32Snapshot == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
HOWTO:使用 Win32 API 枚举应用程序lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
HOWTO:使用 Win32 API 枚举应用程序LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
HOWTO:使用 Win32 API 枚举应用程序if (lpfVDMEnumTaskWOWEx == NULL)
HOWTO:使用 Win32 API 枚举应用程序__leave;
HOWTO:使用 Win32 API 枚举应用程序         }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Get a handle to a Toolhelp snapshot of all processes.
HOWTO:使用 Win32 API 枚举应用程序
hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
HOWTO:使用 Win32 API 枚举应用程序if (hSnapShot == INVALID_HANDLE_VALUE) {
HOWTO:使用 Win32 API 枚举应用程序FreeLibrary(hInstLib);
HOWTO:使用 Win32 API 枚举应用程序return FALSE;
HOWTO:使用 Win32 API 枚举应用程序         }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Get the first process' information.
HOWTO:使用 Win32 API 枚举应用程序
procentry.dwSize = sizeof(PROCESSENTRY32);
HOWTO:使用 Win32 API 枚举应用程序bFlag = lpfProcess32First(hSnapShot, &procentry);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// While there are processes, keep looping.
HOWTO:使用 Win32 API 枚举应用程序
while (bFlag) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Call the enum func with the filename and ProcID.
HOWTO:使用 Win32 API 枚举应用程序
if (lpProc(procentry.th32ProcessID, 0,
HOWTO:使用 Win32 API 枚举应用程序procentry.szExeFile, lParam)) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Did we just bump into an NTVDM?
HOWTO:使用 Win32 API 枚举应用程序
if (_stricmp(procentry.szExeFile, "NTVDM.EXE") == 0) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Fill in some info for the 16-bit enum proc.
HOWTO:使用 Win32 API 枚举应用程序
sInfo.dwPID = procentry.th32ProcessID;
HOWTO:使用 Win32 API 枚举应用程序sInfo.lpProc = lpProc;
HOWTO:使用 Win32 API 枚举应用程序sInfo.lParam = (DWORD) lParam;
HOWTO:使用 Win32 API 枚举应用程序sInfo.bEnd = FALSE;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Enum the 16-bit stuff.
HOWTO:使用 Win32 API 枚举应用程序
lpfVDMEnumTaskWOWEx(procentry.th32ProcessID,
HOWTO:使用 Win32 API 枚举应用程序(TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Did our main enum func say quit?
HOWTO:使用 Win32 API 枚举应用程序
if (sInfo.bEnd)
HOWTO:使用 Win32 API 枚举应用程序break;
HOWTO:使用 Win32 API 枚举应用程序               }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序procentry.dwSize = sizeof(PROCESSENTRY32);
HOWTO:使用 Win32 API 枚举应用程序bFlag = lpfProcess32Next(hSnapShot, &procentry);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序}
 else
HOWTO:使用 Win32 API 枚举应用程序bFlag = FALSE;
HOWTO:使用 Win32 API 枚举应用程序         }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序}
 __finally {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib)
HOWTO:使用 Win32 API 枚举应用程序FreeLibrary(hInstLib);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (hInstLib2)
HOWTO:使用 Win32 API 枚举应用程序FreeLibrary(hInstLib2);
HOWTO:使用 Win32 API 枚举应用程序      }

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序}
 else
HOWTO:使用 Win32 API 枚举应用程序return FALSE;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序// Free the library.
HOWTO:使用 Win32 API 枚举应用程序
FreeLibrary(hInstLib);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序return TRUE;
HOWTO:使用 Win32 API 枚举应用程序}

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
HOWTO:使用 Win32 API 枚举应用程序PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序BOOL bRet;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序EnumInfoStruct *psInfo = (EnumInfoStruct *)lpUserDefined;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序bRet = psInfo->lpProc(psInfo->dwPID, hTask16, pszFileName,
HOWTO:使用 Win32 API 枚举应用程序psInfo->lParam);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (!bRet)
HOWTO:使用 Win32 API 枚举应用程序psInfo->bEnd = TRUE;
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序return !bRet;
HOWTO:使用 Win32 API 枚举应用程序}

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序BOOL CALLBACK MyProcessEnumerator(DWORD dwPID, WORD wTask,
HOWTO:使用 Win32 API 枚举应用程序LPCSTR szProcess, LPARAM lParam) {
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序if (wTask == 0)
HOWTO:使用 Win32 API 枚举应用程序printf("%5u   %s\n", dwPID, szProcess);
HOWTO:使用 Win32 API 枚举应用程序else
HOWTO:使用 Win32 API 枚举应用程序printf("  %5u %s\n", wTask, szProcess);
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序return TRUE;
HOWTO:使用 Win32 API 枚举应用程序}

HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序
HOWTO:使用 Win32 API 枚举应用程序void main() {
HOWTO:使用 Win32 API 枚举应用程序EnumProcs((PROCENUMPROC) MyProcessEnumerator, 0);
HOWTO:使用 Win32 API 枚举应用程序

参考

Pietrek, Matt, "Under the Hood," Microsoft Systems Journal , no. 8 (August 1996).

Pietrek, Matt, "Under the Hood," Microsoft Systems Journal , no. 11 (November 1996).


这篇文章中的信息适用于:
Microsoft Win32 应用程序编程接口 (API)当用于
    Microsoft Windows 95 Service Pack 1
    Microsoft Windows 98 Standard Edition
    Microsoft Windows Millennium Edition
    Microsoft Windows NT 4.0 Service Pack 7
    Microsoft Windows 2000 Standard Edition
    Microsoft Windows XP Standard Edition
关键字: 
kbhowto kbthread kbkernbase kbgrpdskernbase KB175030
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的
上一篇:wordpress搭建个人博客


下一篇:构建理想的模块自测结构