从进程ID获取进程名称(win32)

问题描述:

我需要获取Windows系统上所有进程的列表,包括名称和PID。
EnumProcess可以获得pid列表,但是如何从pid获取进程名称?我不想在流程上调用OpenProcess,因为这并不总是有效(例如,如果另一个流程由不同的用户运行)。从进程ID获取进程名称(win32)

+0

我不认为你可以在Vista之后的Windows版本上可靠地做到这一点。你正在使用哪个版本? – 2010-11-05 00:20:13

+0

你可以使用WMI来做这个 – 2010-11-05 00:56:22

+0

你是什么意思的进程名称--EXE名称? – 2010-11-05 12:15:28

CreateToolhelp32Snapshot()会给你进程名称(但不是路径);除此之外,你将不得不打电话给OpenProcess()。如果您的代码在管理环境中运行,则可以启用SE_DEBUG_NAME特权来访问在其他环境下运行的进程。

您有不同的选项,您可以使用它来接收当前正在运行的进程(进程名称,如您所写的)的exe名称。最好的方式取决于您使用的编程语言和其他需求。例如,您可以使用WMI。另一种更老的方式是使用Performance Counters(另请参阅An Introduction To Performance Counters)。要获取计数器值你可以使用注册表查询操作从HKEY_PERFORMANCE_DATA基本密钥(见Retrieving Counter Data

另一种方式可以是还不错采用的是NtQuerySystemInformation函数SystemProcessInformation作为参数。 EnumProcess和许多其他Windows API在内部使用该函数。在NtQuerySystemInformation文档中定义的结构SYSTEM_PROCESS_INFORMATION有许多“无证”,但自许多年以来众所周知的领域。如果你在互联网上搜索结构的定义,你将被罚款完整的文件。我不知道功能帽状态没有完整记录。该功能至少在NT 3.5(可能还在之前),现在可以很好地用于Windows 7 32位或64位。要确切下面你会发现一个小的C性能测试,其打印所有进程ID与相应的exe文件名(不完整的exe路径,只是文件名):

#include <Windows.h> 
// one can also use Winternl.h if needed 
//#include <Winternl.h> // for UNICODE_STRING and SYSTEM_INFORMATION_CLASS 
#include <stdio.h> 
#include <tchar.h> 

#define STATUS_SUCCESS    ((NTSTATUS)0x00000000L) 
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 

typedef enum _SYSTEM_INFORMATION_CLASS { 
    SystemProcessInformation = 5 
} SYSTEM_INFORMATION_CLASS; 

typedef struct _UNICODE_STRING { 
    USHORT Length; 
    USHORT MaximumLength; 
    PWSTR Buffer; 
} UNICODE_STRING; 

typedef LONG KPRIORITY; // Thread priority 

typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD { 
    ULONG NextEntryOffset; 
    ULONG NumberOfThreads; 
    LARGE_INTEGER SpareLi1; 
    LARGE_INTEGER SpareLi2; 
    LARGE_INTEGER SpareLi3; 
    LARGE_INTEGER CreateTime; 
    LARGE_INTEGER UserTime; 
    LARGE_INTEGER KernelTime; 
    UNICODE_STRING ImageName; 
    KPRIORITY BasePriority; 
    HANDLE UniqueProcessId; 
    ULONG InheritedFromUniqueProcessId; 
    ULONG HandleCount; 
    BYTE Reserved4[4]; 
    PVOID Reserved5[11]; 
    SIZE_T PeakPagefileUsage; 
    SIZE_T PrivatePageCount; 
    LARGE_INTEGER Reserved6[6]; 
} SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD; 

typedef NTSTATUS (WINAPI *PFN_NT_QUERY_SYSTEM_INFORMATION)(
    IN  SYSTEM_INFORMATION_CLASS SystemInformationClass, 
    IN OUT PVOID SystemInformation, 
    IN  ULONG SystemInformationLength, 
    OUT OPTIONAL PULONG ReturnLength 
); 

int main() 
{ 
    size_t bufferSize = 102400; 
    PSYSTEM_PROCESS_INFORMATION_DETAILD pspid= 
     (PSYSTEM_PROCESS_INFORMATION_DETAILD) malloc (bufferSize); 
    ULONG ReturnLength; 
    PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION) 
     GetProcAddress (GetModuleHandle(TEXT("ntdll.dll")), "NtQuerySystemInformation"); 
    NTSTATUS status; 

    while (TRUE) { 
     status = pfnNtQuerySystemInformation (SystemProcessInformation, (PVOID)pspid, 
               bufferSize, &ReturnLength); 
     if (status == STATUS_SUCCESS) 
      break; 
     else if (status != STATUS_INFO_LENGTH_MISMATCH) { // 0xC0000004L 
      _tprintf (TEXT("ERROR 0x%X\n"), status); 
      return 1; // error 
     } 

     bufferSize *= 2; 
     pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD) realloc ((PVOID)pspid, bufferSize); 
    } 

    for (;; 
     pspid=(PSYSTEM_PROCESS_INFORMATION_DETAILD)(pspid->NextEntryOffset + (PBYTE)pspid)) { 

     _tprintf (TEXT("ProcessId: %d, ImageFileName: %ls\n"), pspid->UniqueProcessId, 
      (pspid->ImageName.Length && pspid->ImageName.Buffer)? pspid->ImageName.Buffer: L""); 

     if (pspid->NextEntryOffset == 0) break; 
    } 

    return 0; 
} 
+2

太棒了!为我节省了很多时间。只是一个侧面说明:有一个内存泄漏,你不能释放“pspid”。尽管如此:-) – Dan 2011-02-01 17:32:34

+0

“修复”内存泄漏非常容易。只有你使用代码作为函数的一部分才是真正需要的。要做到这一点,你只需要在另一个变量的第一个循环之后保存'pspid'的值(因为在当前代码中该值将被修改)并且用指针调用'free'。 – Oleg 2012-05-30 19:10:02

,你可以得到的进程标识符和name所有正在运行的进程使用ToolHelp API。
以下代码将显示每个进程的pidname

void showProcessInformation() { 
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    if(hSnapshot) { 
     PROCESSENTRY32 pe32; 
     pe32.dwSize = sizeof(PROCESSENTRY32); 
     if(Process32First(hSnapshot, &pe32)) { 
      do { 
       printf("pid %d %s\n", pe32.th32ProcessID, pe32.szExeFile); 
      } while(Process32Next(hSnapshot, &pe32)); 
     } 
     CloseHandle(hSnapshot); 
    } 
} 
+2

您只需要使用: pe32.dwSize = sizeof(PROCESSENTRY32);在调用Process32First() – hB0 2012-02-13 13:59:20

+1

@ hB0之前 - 错过了那个=) – Cyclonecode 2012-02-13 16:01:06

+1

这真的很酷,比'NtQuerySystemInformation'技术快得多。有没有什么方法可以通过这种技术获得PID创建时间? – Noitidart 2016-01-10 13:03:10