potisanのプログラミングメモ

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

C++20&Win API&WIL バッテリーデバイスの名前を列挙する

C++20・Win API・WILでバッテリーデバイスの名前を列挙するサンプルコードです。

#include <functional>
#include <string>
#include <vector>

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

#include "wil/resource.h"

struct hdevinfo_invalid_resource_policy : wil::details::resource_policy<
    HDEVINFO,
    decltype(&::SetupDiDestroyDeviceInfoList),
    &::SetupDiDestroyDeviceInfoList,
    wil::details::pointer_access_all,
    HDEVINFO,
    INT_PTR,
    -1,
    HDEVINFO>
{
    __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); }
};

using unique_hdevinfo = wil::unique_any_t<wil::details::unique_storage<hdevinfo_invalid_resource_policy>>;

std::wstring SetupDiGetDevicePropertyWString(
    HDEVINFO DeviceInfoSet,
    PSP_DEVINFO_DATA DeviceInfoData,
    CONST DEVPROPKEY& PropertyKey,
    DWORD Flags)
{
    DWORD propType = 0;
    DWORD propSize = 0;
    ::SetupDiGetDevicePropertyW(DeviceInfoSet, DeviceInfoData,
        &PropertyKey, &propType, nullptr, 0, &propSize, Flags);
    if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && propType == DEVPROP_TYPE_STRING)
    {
        std::wstring buffer(propSize / sizeof(wchar_t) - 1, L'\0');
        if (::SetupDiGetDevicePropertyW(DeviceInfoSet, DeviceInfoData,
            &PropertyKey, &propType, reinterpret_cast<PBYTE>(buffer.data()),
            propSize, &propSize, Flags))
        {
            return buffer;
        }
    }
    return {};
}

void EnumerateSetupDiDeviceInfos(
    HDEVINFO DeviceInfoSet,
    std::function<void(HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA& Data, DWORD MemberIndex)> fn)
{
    SP_DEVINFO_DATA data{ sizeof(SP_DEVINFO_DATA) };
    for (DWORD i = 0; ::SetupDiEnumDeviceInfo(DeviceInfoSet, i, &data); i++)
        fn(DeviceInfoSet, data, i);
}

#include <iostream>

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

    unique_hdevinfo hdevinfo(::SetupDiGetClassDevsW(
        &GUID_DEVCLASS_BATTERY, nullptr, nullptr, DIGCF_PRESENT));
    EnumerateSetupDiDeviceInfos(hdevinfo.get(),
        [](HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA& Data, DWORD MemberIndex)
        {
            auto description = SetupDiGetDevicePropertyWString(
                DeviceInfoSet, &Data, DEVPKEY_Device_DeviceDesc, 0);
            std::wcout << description << std::endl;
        });

    return 0;
}