进程ID和进程名称

时间:2011-05-02 13:48:49

标签: c++ c windows winapi

我正在创建一个基本扫描系统的Windows程序,以查看特定进程是否正在运行。我有进程名称(AcroRd32.exe),没有别的。

从我读过的最简单的方法是使用 CreateToolhelp32Snapshot 创建所有进程的快照,然后遍历每个进程以查找进程名称。

我的应用程序非常以性能为中心。那么有更好的更有效的方法来做到这一点。 应用程序每隔几秒收集一次快照。迭代快照中的100个进程似乎效率不高。是否有直接API可以通过其进程名称找到进程(并通过名称检索进程句柄或id)?

我没有太多运气就广泛搜索过。有人曾尝试过这个吗?

2 个答案:

答案 0 :(得分:4)

扫描进程的最快方法是通过NTDLL的NtQuerySystemInformation调用。它通过一次调用为您提供系统上所有进程的名称和进程ID列表(在极少数情况下,即大量进程)。您可以组合NtQuerySystemInformation并使用哈希来进行字符串比较,而不是比较每个字节。

// headers @ http://pastebin.com/HWzJYpbv


NtQuerySystemInformation = (_RT_NAPI_QUERYSYSINFO)GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtQuerySystemInformation");

    // Get process information buffer
    do {
        // Allocate buffer for process info
        pBuffer = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cbBuffer); 
        if (pBuffer == NULL) {
            // Cannot allocate enough memory for buffer (CRITICAL ERROR)
            return 1;
        }

        // Obtain system process snapshot
        Status = NtQuerySystemInformation(5, pBuffer, cbBuffer, NULL);

        // Allocate bigger buffer for moar data
        if (Status == STATUS_INFO_LENGTH_MISMATCH) {
            HeapFree(hHeap, 0, pBuffer);
            cbBuffer *= 2; // Increase the size of the buffer :-)
        } else if ((Status) != 0x00) {
            // Can't query process information (probably rootkit or anti-virus)
            HeapFree(hHeap, 0, pBuffer);
            return 1;
        }
    } while (Status == STATUS_INFO_LENGTH_MISMATCH);

    // Get pointer to first system process info structure
    pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;

    // Loop over each process
    for (;;) {
        // Get process name
        pszProcessName = pInfo->ImageName.Buffer;

        // ... do work. For a fast string compare, calculate a 32-bit hash of the string, then compare to a static hash.
        if(CRC32(pszProcessName) == 0xDEADBEEF /* <- hash of adobe reader process name goez here */) {
            // Found process
        }

        // Load next entry
        if (pInfo->NextEntryOffset == 0)
            break;
        pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo)+ pInfo->NextEntryOffset);
    }

在Windows 2000上测试 - Windows 7英文版,x64 / x86(Win XP x64除外) 注意:它将在64位系统上将所有进程返回到32位WOW64进程。

答案 1 :(得分:3)

每个流程都有唯一ID ,但不是唯一名称。可能有多个具有相同名称的进程。因此,如果不迭代所有进程,就不可能直接从其名称中获取进程句柄。

在内部所有的行为以某种方式链接在一起,例如,在链表中。即使提供了一个函数GetProcessByName(),它也会在内部遍历列表,以便代表您查找具有该名称的进程。所以这不会对性能产生很大的影响。

<强>除了

EnumProcesses()投射,其开销较小且更简单。检查here

BOOL WINAPI EnumProcesses(
  __out  DWORD *pProcessIds,
  __in   DWORD cb,
  __out  DWORD *pBytesReturned
);

MSDN对此有一个example