web-dev-qa-db-ja.com

プロセスIDからプロセス名を取得(win32)

名前とPIDを含むWindowsシステム上のすべてのプロセスのリストを取得する必要があります。
EnumProcess pidのリストを取得できますが、pidからプロセス名を取得するにはどうすればよいですか? (他のプロセスが別のユーザーによって実行されている場合など)常に機能するとは限らないため、プロセスでOpenProcessを呼び出したくありません。

20
David Chen

ToolHelp APIを使用して、実行中のすべてのプロセスのプロセス識別子とnameを取得できます。
次のコードは、各プロセスのpidおよびnameを表示します。

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);
    }
}
17
Cyclonecode

現在実行中のプロセス(書いたようなプロセス名)のexe名を受け取るために使用できる別のオプションがあります。最良の方法は、使用するプログラミング言語やその他の要件によって多少異なります。たとえば、WMIを使用できます。もう1つの古い方法は、 パフォーマンスカウンター の使用です( パフォーマンスカウンターの概要 も参照)。カウンター値を取得するには、HKEY_PERFORMANCE_DATA基本キーからレジストリクエリ操作を使用するだけです( Retrieving Counter Data を参照)。

よく使用できるもう1つの方法は、パラメーターとしてSystemProcessInformationを指定した NtQuerySystemInformation 関数です。 EnumProcessおよび他の多くのWindows APIは、関数を内部で使用します。 NtQuerySystemInformation のドキュメントで定義されているSYSTEM_PROCESS_INFORMATIONには、多くの「ドキュメント化されていない」が、長年にわたってよく知られているフィールドがある。インターネットで構造の定義を検索すると、完全なドキュメントが作成されます。関数ハットのステータスが完全に文書化されていないと思います。この機能は少なくともNT 3.5にあり(おそらく以前にも)、Windows 7の32ビットまたは64ビットで現在十分に使用できます。正確には、対応するexe名(完全なexeパスではなく、ファイル名のみ)を持つすべてのプロセスIDを出力する小さなCテストプログラムがあります。

#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;
}
16
Oleg

CreateToolhelp32Snapshot()はプロセス名を与えます(パスは与えません)。それ以外の場合は、OpenProcess()を呼び出す必要があります。コードが管理コンテキストで実行されている場合、SE_DEBUG_NAME特権を有効にして、他のコンテキストで実行されているプロセスにアクセスできます。

5
Luke