potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。

C++20&Win API(Vista~) 各電源スキームのサブグループのGUID・名前・概要を列挙する

#include <format>
#include <iostream>
#include <string>
#include <vector>
#include <optional>

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

namespace PowerUtil
{
    std::vector<GUID> GetPowerSchemeGUIDs()
    {
        std::vector<GUID> guids;
        for (ULONG i = 0; ; ++i)
        {
            GUID guid;
            DWORD guidSize{ sizeof(GUID) };
            auto ret = ::PowerEnumerate(
                nullptr, nullptr, nullptr,
                ACCESS_SCHEME,
                i,
                reinterpret_cast<UCHAR*>(&guid), &guidSize);
            if (ret != NOERROR)
                break;
            guids.emplace_back(guid);
        }
        return std::move(guids);
    }

    std::vector<GUID> GetSubGroupOfPowerSettingsGUIDs(const GUID* powerSchemeGuid)
    {
        std::vector<GUID> guids;
        for (ULONG i = 0; ; ++i)
        {
            GUID guid;
            DWORD guidSize{ sizeof(GUID) };
            auto ret = ::PowerEnumerate(
                nullptr, powerSchemeGuid, nullptr,
                ACCESS_SUBGROUP,
                i,
                reinterpret_cast<UCHAR*>(&guid), &guidSize);
            if (ret != NOERROR)
                break;
            guids.emplace_back(guid);
        }
        return std::move(guids);
    }

    std::optional<std::wstring> ReadDescription(
        const GUID* SchemeGuid,
        const GUID* SubGroupOfPowerSettingsGuid,
        const GUID* PowerSettingGuid)
        noexcept(false)
    {
        DWORD bufferSize;
        if (::PowerReadDescription(
            nullptr,
            SchemeGuid,
            SubGroupOfPowerSettingsGuid,
            PowerSettingGuid,
            nullptr, &bufferSize) != NOERROR)
        {
            return {};
        }

        std::wstring buffer(bufferSize / sizeof(wchar_t) - 1, L'\0');
        if (::PowerReadDescription(
            nullptr,
            SchemeGuid,
            SubGroupOfPowerSettingsGuid,
            PowerSettingGuid,
            reinterpret_cast<PUCHAR>(buffer.data()),
            &bufferSize) != NOERROR)
        {
            return {};
        }
        return std::move(buffer);
    }

    std::optional<std::wstring> ReadFriendlyName(
        const GUID* SchemeGuid,
        const GUID* SubGroupOfPowerSettingsGuid,
        const GUID* PowerSettingGuid)
        noexcept(false)
    {
        DWORD bufferSize;
        if (::PowerReadFriendlyName(
            nullptr,
            SchemeGuid,
            SubGroupOfPowerSettingsGuid,
            PowerSettingGuid,
            nullptr, &bufferSize) != NOERROR)
        {
            return {};
        }

        std::wstring buffer(bufferSize / sizeof(wchar_t) - 1, L'\0');
        if (::PowerReadFriendlyName(
            nullptr,
            SchemeGuid,
            SubGroupOfPowerSettingsGuid,
            PowerSettingGuid,
            reinterpret_cast<PUCHAR>(buffer.data()),
            &bufferSize) != NOERROR)
        {
            return {};
        }
        return std::move(buffer);
    }
}

namespace GUIDUtil
{
    std::wstring GUIDToWString(const GUID& guid)
    {
        std::wstring buffer(38, L'\0');
        return SUCCEEDED(::StringFromGUID2(guid, buffer.data(), 39))
            ? std::move(buffer)
            : std::wstring{};
    }
}

inline const wchar_t* strptr_not_null(const std::optional<std::wstring>& s) {
    return !s ? L"" : s->data();
}

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

    // 電源スキームGUIDを列挙する。
    auto powerSchemeGuids = PowerUtil::GetPowerSchemeGUIDs();
    for (const auto& powerSchemeGuid : powerSchemeGuids)
    {
        std::wcout
            << std::format(L"■{}: {}",
                GUIDUtil::GUIDToWString(powerSchemeGuid),
                strptr_not_null(PowerUtil::ReadFriendlyName(&powerSchemeGuid, nullptr, nullptr)))
            << std::endl;

        auto subGroupGuids = PowerUtil::GetSubGroupOfPowerSettingsGUIDs(&powerSchemeGuid);
        for (const auto& subGroupGuid : subGroupGuids)
        {
            std::wcout
                << std::format(L"{}: {} - {}",
                    GUIDUtil::GUIDToWString(subGroupGuid),
                    strptr_not_null(PowerUtil::ReadFriendlyName(&powerSchemeGuid, &subGroupGuid, nullptr)),
                    strptr_not_null(PowerUtil::ReadDescription(&powerSchemeGuid, &subGroupGuid, nullptr)))
                << std::endl;
        }

        std::wcout << std::endl;
    }

    return 0;
}