potisanのプログラミングメモ

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

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;
}