potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。

C++20&Win API Setup APIでシステムに存在するデバイスのクラス・インターフェイスのクラスと説明を列挙する

Setup APIでシステムに存在するデバイスのクラス・インターフェイスのクラスと説明を列挙するコードです。

単純に列挙する

#pragma comment(lib, "SetupAPI.lib")

#include <bit>
#include <format>
#include <string>

#define STRICT
#include <Windows.h>
#include <SetupAPI.h>
#include <InitGUID.h>
#include <devpkey.h>

// デバイスの文字列型プロパティを取得します。
std::wstring GetDevicePropertyString(
    HDEVINFO          DeviceInfoSet,
    PSP_DEVINFO_DATA  DeviceInfoData,
    const DEVPROPKEY* PropertyKey,
    DWORD             Flags)
{
    DEVPROPTYPE PropType;
    DWORD Size;
    if (!SetupDiGetDevicePropertyW(
        DeviceInfoSet, DeviceInfoData, PropertyKey, &PropType,
        nullptr, 0, &Size, 0)
        && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    {
        return {};
    }
    std::wstring buffer(Size - 1, L'\0');
    if (!SetupDiGetDevicePropertyW(
        DeviceInfoSet, DeviceInfoData, PropertyKey, &PropType,
        std::bit_cast<PBYTE>(buffer.data()), Size, &Size, 0))
    {
        return {};
    }
    return std::move(buffer);
}

#include <iostream>

void main()
{
    std::wcout.imbue(std::locale("", std::locale::ctype));

    // 現在システムに存在する全てのクラス・インターフェイスを列挙
    std::wcout << L"DIGCF_ALLCLASSES | DIGCF_PRESENT" << std::endl;
    HDEVINFO DevInfoHandle = SetupDiGetClassDevs(
        nullptr, nullptr, nullptr,
        DIGCF_ALLCLASSES | DIGCF_PRESENT);
    SP_DEVINFO_DATA DevInfoData{ sizeof(SP_DEVINFO_DATA) };
    for (DWORD i = 0; SetupDiEnumDeviceInfo(DevInfoHandle, i, &DevInfoData); i++)
    {
        auto ClassName{ GetDevicePropertyString(
            DevInfoHandle,
            &DevInfoData,
            &DEVPKEY_Device_Class,
            0) };
        auto DeviceDesc{ GetDevicePropertyString(
            DevInfoHandle,
            &DevInfoData,
            &DEVPKEY_Device_DeviceDesc,
            0) };
        std::wcout
            << std::format(L"{} - {}", ClassName, DeviceDesc)
            << std::endl;
    }
    SetupDiDestroyDeviceInfoList(DevInfoHandle);
}

分類して列挙する

#include <bit>
#include <format>
#include <string>

#pragma comment(lib, "SetupAPI.lib")
#define STRICT
#include <Windows.h>
#include <SetupAPI.h>
#include <InitGUID.h>
#include <devpkey.h>

// デバイスの文字列型プロパティを取得します。
std::wstring GetDevicePropertyString(
    HDEVINFO          DeviceInfoSet,
    PSP_DEVINFO_DATA  DeviceInfoData,
    const DEVPROPKEY* PropertyKey,
    DWORD             Flags)
{
    DEVPROPTYPE PropType;
    DWORD Size;
    if (!SetupDiGetDevicePropertyW(
        DeviceInfoSet, DeviceInfoData, PropertyKey, &PropType,
        nullptr, 0, &Size, 0)
        && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    {
        return {};
    }
    std::wstring buffer(Size - 1, L'\0');
    if (!SetupDiGetDevicePropertyW(
        DeviceInfoSet, DeviceInfoData, PropertyKey, &PropType,
        std::bit_cast<PBYTE>(buffer.data()), Size, &Size, 0))
    {
        return {};
    }
    return std::move(buffer);
}

#include <iostream>
#include <map>
#include <vector>

int main()
{
    // std::wcoutの日本語文字化けを回避
    std::wcout.imbue(std::locale("", std::locale::ctype));

    // 現在システムに存在する全てのクラス・インターフェイスを列挙
    // クラス毎に説明をまとめる
    std::wcout << "DIGCF_ALLCLASSES | DIGCF_PRESENT" << std::endl;
    HDEVINFO DevInfoHandle = SetupDiGetClassDevs(
        nullptr, nullptr, nullptr,
        DIGCF_ALLCLASSES | DIGCF_PRESENT);
    SP_DEVINFO_DATA DevInfoData = { sizeof SP_DEVINFO_DATA };
    std::map<std::wstring, std::vector<std::wstring>> ClassDescMap;
    for (DWORD i = 0; SetupDiEnumDeviceInfo(DevInfoHandle, i, &DevInfoData); i++)
    {
        auto ClassName{ GetDevicePropertyString(
            DevInfoHandle, &DevInfoData, &DEVPKEY_Device_Class, 0) };
        auto DeviceDesc{ GetDevicePropertyString(
            DevInfoHandle, &DevInfoData, &DEVPKEY_Device_DeviceDesc, 0) };
        ClassDescMap[ClassName].push_back(DeviceDesc);
    }
    SetupDiDestroyDeviceInfoList(DevInfoHandle);

    // 列挙したクラス毎の説明を出力
    for (const auto& ClassDescPair : ClassDescMap)
    {
        std::wcout << ClassDescPair.first.c_str() << std::endl;
        for (const auto& Desc : ClassDescPair.second)
        {
            std::wcout << std::format(L"\t{}", Desc.c_str()) << std::endl;
        }
    }

    return 0;
}