potisanのプログラミングメモ

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

C++17&Win32 API デバイス情報要素のGUID、不透明ハンドル、概要を列挙する

バイス情報要素のGUID、不透明ハンドル(Opaque Handle)、概要を列挙するサンプルコードです。C++&Win32 API デバイス情報要素のGUIDと不透明ハンドルを列挙するの拡張です。

#include <array>
#include <memory>
#include <string>
#include <numeric>
#include <iostream>
#include <tuple>
#include <list>

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

using namespace std;

using unique_devinfo_handle = unique_ptr<remove_pointer_t<HDEVINFO>,
    decltype(&::SetupDiDestroyDeviceInfoList)>;

unique_devinfo_handle make_unique_devinfo_handle(HDEVINFO handle) noexcept;
unique_devinfo_handle unique_SetupDiGetClassDevsW(
    const GUID* ClassGuid,
    LPCWSTR Enumerator,
    HWND hWndParent,
    DWORD Flags) noexcept;
wstring guid_to_wstring(const GUID& guid);
list<tuple<GUID, DWORD>> SetupDiEnumDeviceInfo_list(HDEVINFO DeviceInfoSet) noexcept;

int main()
{
    wcout.imbue(locale("Japanese", locale::ctype));

    auto devinfo_handle = unique_SetupDiGetClassDevsW(
        nullptr,
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES);
    auto devinfos = SetupDiEnumDeviceInfo_list(devinfo_handle.get());

    wcout << L"ClassGuid, DevInst, Class Description" << endl;
    array<wchar_t, LINE_LEN> class_des;
    for (const auto& [ClassGuid, DevInst] : devinfos)
    {
        ::SetupDiGetClassDescriptionExW(&ClassGuid,
            class_des.data(), class_des.size(), nullptr, nullptr, nullptr);
        wcout << guid_to_wstring(ClassGuid) << L", " << DevInst << L", " << class_des.data() << endl;
    }
}

unique_devinfo_handle make_unique_devinfo_handle(HDEVINFO handle) noexcept
{
    return unique_devinfo_handle(handle, &::SetupDiDestroyDeviceInfoList);
}

unique_devinfo_handle unique_SetupDiGetClassDevsW(
    const GUID* ClassGuid,
    LPCWSTR Enumerator,
    HWND hWndParent,
    DWORD Flags) noexcept
{
    return make_unique_devinfo_handle(
        ::SetupDiGetClassDevsW(ClassGuid, Enumerator, hWndParent, Flags));
}

wstring guid_to_wstring(const GUID& guid)
{
    LPWSTR s;
    if (FAILED(StringFromCLSID(guid, &s)))
        return {};
    wstring str = s;
    CoTaskMemFree(s);
    return move(str);
}

list<tuple<GUID, DWORD>> SetupDiEnumDeviceInfo_list(HDEVINFO DeviceInfoSet) noexcept
{
    list<tuple<GUID, DWORD>> list;
    for (DWORD i = 0; i < numeric_limits<DWORD>::max(); i++)
    {
        SP_DEVINFO_DATA data{ sizeof(data) };
        if (!::SetupDiEnumDeviceInfo(DeviceInfoSet, i, &data))
        {
            break;
        }
        list.emplace_back(data.ClassGuid, data.DevInst);
    }
    return move(list);
}