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