potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

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

Windows NT系列でデバイス情報要素のGUIDと不透明ハンドル(Opaque Handle)を列挙するサンプルコードです。

SP_DEVINFO_DATA構造体として取得する

最も単純な方法としてSP_DEVINFO_DATA構造体のまま取得するサンプルコードです。追記:一部のSetup APISetupDiGetDeviceRegistryPropertyW等)はReserved0SP_DEVINFO_DATAインスタンスを与えると不正なパラメーターで失敗するため、下記のタプルにするよりもこちらの方が良いかもしれません。

SetupDiDestroyDeviceInfoList関数に与えるフラグにより列挙される情報を制限できます。ここではDIGCF_ALLCLASSESを与えてすべての情報を列挙しています。なお、unique_SetupDiGetClassDevsW関数はSetupDiDestroyDeviceInfoList関数のHDEVINFO型戻り値をunique_ptrで扱うためのラッパー関数です。

#include <memory>
#include <string>
#include <numeric>
#include <iostream>

#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);

int main()
{
    auto devinfo_handle = unique_SetupDiGetClassDevsW(
        nullptr,
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES);

    wcout << L"ClassGuid, DevInst" << endl;
    for (DWORD i = 0; i < numeric_limits<DWORD>::max(); i++)
    {
        SP_DEVINFO_DATA data{ sizeof(data) };
        if (!::SetupDiEnumDeviceInfo(devinfo_handle.get(), i, &data))
        {
            break;
        }
        wcout << guid_to_wstring(data.ClassGuid) << L", " << data.DevInst << 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);
}

GUID ClassGuidDWORD DevInstのタプルリストとして取得する

SP_DEVINFO_DATA構造体からtuple<GUID, DWORD>のリストを作成した後、構造化束縛によりGUID ClassGuidDWORD DevInstを列挙するサンプルコードです。

#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
{
    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);
}

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

    wcout << L"ClassGuid, DevInst" << endl;
    for (const auto& [ClassGuid, DevInst] : devinfos)
    {
        wcout << guid_to_wstring(ClassGuid) << L", " << DevInst << 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);
}