potisanのプログラミングメモ

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

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

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

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

    // 電源スキームGUIDを列挙する。
    auto powerSchemeGuids = PowerUtil::GetPowerSchemeGUIDs();

    for (const auto& powerSchemeGuid : powerSchemeGuids)
    {
        auto friendlyName = PowerUtil::ReadFriendlyName(&powerSchemeGuid, &GUID_VIDEO_SUBGROUP, nullptr);
        auto description = PowerUtil::ReadDescription(&powerSchemeGuid, &NO_SUBGROUP_GUID, nullptr);

        std::wcout
            << GUIDUtil::GUIDToWString(powerSchemeGuid) << std::endl
            << *friendlyName << std::endl
            << *description << std::endl
            << std::endl;
    }

    return 0;
}