potisanのプログラミングメモ

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

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