potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

C++20&Win API プロセスのIDとパスを列挙する

Win32 APIEnumProcesses関数、QueryFullProcessImageNameW関数を使ってプロセスのIDとパスを列挙するサンプルコードです。

#include <string>
#include <memory>
#include <vector>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <Psapi.h>

template <DWORD InitSize = 100, DWORD ExpandingSize = 100>
std::vector<DWORD> GetAllProcessIDs()
{
    std::vector<DWORD> processIds;

    for (DWORD size = InitSize;; size += ExpandingSize)
    {
        processIds.resize(size);
        DWORD cbNeeded;
        DWORD cbSize = size * sizeof(DWORD);
        if (!EnumProcesses(processIds.data(), cbSize, &cbNeeded))
        {
            return {};
        }
        if (cbNeeded < cbSize)
        {
            processIds.resize(cbNeeded / sizeof(DWORD));
            processIds.shrink_to_fit();
            return processIds;
        }
    }
}

struct unique_handle_deleter {
    inline void operator()(HANDLE h) const {
        CloseHandle(h);
    }
};
using unique_handle = std::unique_ptr<std::remove_pointer_t<HANDLE>, unique_handle_deleter>;

template <DWORD InitSize = 100, DWORD ExpandingSize = 100>
std::wstring QueryFullProcessImageNameW(HANDLE processHandle, DWORD flags)
{
    std::wstring s;
    for (DWORD size = InitSize;; size += ExpandingSize)
    {
        s.resize(size);
        DWORD cch = size;
        if (QueryFullProcessImageNameW(processHandle, flags, s.data(), &cch))
        {
            s.resize(cch);
            s.shrink_to_fit();
            return s;
        }
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        {
            return {};
        }
    }
}

#include <filesystem>
#include <format>
#include <iostream>

int main()
{
    for (auto processId : GetAllProcessIDs())
    {
        unique_handle processHandle(
            OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId));
        auto path = std::filesystem::path(QueryFullProcessImageNameW(processHandle.get(), 0));

        // プロセスID、ファイル名、場所
        std::wcout
            << std::format(L"{}, {}, {}", processId, path.filename().native(), path.parent_path().native())
            << std::endl;
    }

    return 0;
}