potisanのプログラミングメモ

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

C++17&Win32 API デバイス情報要素の文字列プロパティ(概要、クラス、クラスGUID、フレンドリーネーム、ハードウェアID)を列挙・整理する

バイス情報要素の文字列プロパティ(概要、クラス、クラスGUID、フレンドリーネーム、ハードウェアID)を列挙するコードです。再利用可能なコードをUtility.hppへ移動しています。

文字列プロパティ(概要、クラス、クラスGUID、フレンドリーネーム、ハードウェアID)を列挙する

Main.cpp

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

#include "Utility.hpp"

using namespace std;

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

    auto DevInfoHandle = unique_SetupDiGetClassDevsW(
        nullptr,
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES);

    // ループ中で繰り返し使用するバッファーの用意
    wstring DevDesc;
    wstring DevClass;
    wstring DevClassGuid;
    wstring DevFriendlyName;
    wstring DevHardwareId;

    wcout << L"ClassGuid, DevInst, SPDRP_DEVICEDESC, SPDRP_CLASS, SPDRP_CLASSGUID, SPDRP_FRIENDLYNAME, SPDRP_HARDWAREID" << endl;
    for (auto& DevInfoData : SetupDiCreateDeviceInfoDataList(DevInfoHandle.get()))
    {
        SetupDiGetDeviceRegistryPropertyAsStringW(DevDesc,
            DevInfoHandle.get(), &DevInfoData, SPDRP_DEVICEDESC);
        SetupDiGetDeviceRegistryPropertyAsStringW(DevClass,
            DevInfoHandle.get(), &DevInfoData, SPDRP_CLASS);
        SetupDiGetDeviceRegistryPropertyAsStringW(DevClassGuid,
            DevInfoHandle.get(), &DevInfoData, SPDRP_CLASSGUID);
        SetupDiGetDeviceRegistryPropertyAsStringW(DevFriendlyName,
            DevInfoHandle.get(), &DevInfoData, SPDRP_FRIENDLYNAME);
        SetupDiGetDeviceRegistryPropertyAsStringW(DevHardwareId,
            DevInfoHandle.get(), &DevInfoData, SPDRP_HARDWAREID);

        wcout << guid_to_wstring(DevInfoData.ClassGuid) << L", "
            << DevInfoData.DevInst << L", "
            << DevDesc.c_str() << L", "
            << DevClass.c_str() << L", "
            << DevClassGuid.c_str() << L", "
            << DevFriendlyName.c_str() << L", "
            << DevHardwareId.c_str() << endl;
    }
}

取得したクラスプロパティの値(SPDRP_CLASS)をunique_SetupDiGetClassDevsW関数のEnumerator引数に与えれば取得するデバイス情報要素を制限できます。

Utility.hpp

//-----------------------------------------------------------------------------
// Utility.hpp
// 再利用可能なコードを定義します。
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// GUID -> wstring
//-----------------------------------------------------------------------------

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

//-----------------------------------------------------------------------------
// Setup API wrappers
//-----------------------------------------------------------------------------

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

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

std::list<SP_DEVINFO_DATA> SetupDiCreateDeviceInfoDataList(HDEVINFO DeviceInfoSet)
{
    std::list<SP_DEVINFO_DATA> DevInfoDatas;
    for (DWORD i = 0; i < std::numeric_limits<DWORD>::max(); i++)
    {
        SP_DEVINFO_DATA DevInfoData{ sizeof(SP_DEVINFO_DATA) };
        if (!SetupDiEnumDeviceInfo(DeviceInfoSet, i, &DevInfoData))
        {
            break;
        }
        DevInfoDatas.emplace_back(DevInfoData);
    }
    return std::move(DevInfoDatas);
}

BOOL SetupDiGetDeviceRegistryPropertyAsStringW(
    std::wstring& result,
    HDEVINFO DeviceInfoSet,
    PSP_DEVINFO_DATA DeviceInfoData,
    DWORD Property)
{
    DWORD RequiredSize;
    DWORD PropertyRegDataType;
    if (!SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData,
        Property, &PropertyRegDataType, nullptr, 0, &RequiredSize))
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        {
            return FALSE;
        }
    }
    if (PropertyRegDataType != REG_SZ)
    {
        SetLastError(ERROR_INVALID_DATATYPE);
        return FALSE;
    }

    result.resize(RequiredSize);
    return SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData,
        Property, nullptr, reinterpret_cast<PBYTE>(result.data()), result.size(), nullptr);
}

クラスを列挙する

Utility.hppを使用してクラスを列挙するサンプルコードです。

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

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

#include "Utility.hpp"

using namespace std;

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

    auto DevInfoHandle = unique_SetupDiGetClassDevsW(
        nullptr,
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES);

    set<wstring> DevClassSet;
    wstring Buffer; // ループ中で繰り返し使用するバッファー
    for (auto& DevInfoData : SetupDiCreateDeviceInfoDataList(DevInfoHandle.get()))
    {
        SetupDiGetDeviceRegistryPropertyAsStringW(Buffer,
            DevInfoHandle.get(), &DevInfoData, SPDRP_CLASS);
        DevClassSet.emplace(Buffer.c_str());
    }

    // クラスの列挙
    for (const auto& DevClass : DevClassSet)
    {
        wcout << DevClass << endl;
    }
}

出力例

AudioEndpoint
Battery
CDROM
Computer
DiskDrive
Display
HDC
HIDClass
Image
Keyboard
MEDIA
Monitor
Mouse
Net
PrintQueue
Processor
SCSIAdapter
SoftwareDevice
System
USB
Volume
VolumeSnapshot
WPD
WSDPrintDevice

クラスに対応するデバイス情報要素の概要を列挙する

Utility.hppを使用してクラスに対応するデバイス情報要素の概要を列挙するサンプルコードです。

#include <memory>
#include <string>
#include <numeric>
#include <iostream>
#include <tuple>
#include <list>
#include <map>
#include <vector>

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

#include "Utility.hpp"

using namespace std;

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

    auto DevInfoHandle = unique_SetupDiGetClassDevsW(
        nullptr,
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES);

    map<wstring, vector<wstring>> DevClassMap;
    wstring DevClassBuffer;
    wstring DevDescBuffer;
    for (auto& DevInfoData : SetupDiCreateDeviceInfoDataList(DevInfoHandle.get()))
    {
        SetupDiGetDeviceRegistryPropertyAsStringW(DevClassBuffer,
            DevInfoHandle.get(), &DevInfoData, SPDRP_CLASS);
        SetupDiGetDeviceRegistryPropertyAsStringW(DevDescBuffer,
            DevInfoHandle.get(), &DevInfoData, SPDRP_DEVICEDESC);

        DevClassMap[DevClassBuffer.c_str()].emplace_back(DevDescBuffer.c_str());
    }

    // クラスの列挙
    for (const auto& [DevClass, DevDescs] : DevClassMap)
    {
        wcout << DevClass << L": ";
        for (const auto& DevDesc : DevDescs)
        {
            wcout << DevDesc << L", ";
        }
        wcout << endl << endl;
    }
}