2010-11-05 76 views
17

我需要獲取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

回答

5

CreateToolhelp32Snapshot()會給你進程名稱(但不是路徑);除此之外,你將不得不打電話給OpenProcess()。如果您的代碼在管理環境中運行,則可以啓用SE_DEBUG_NAME特權來訪問在其他環境下運行的進程。

14

您有不同的選項,您可以使用它來接收當前正在運行的進程(進程名稱,如您所寫的)的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

16

,你可以得到的進程標識符和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