もくじ
https://tera1707.com/entry/2022/02/06/144447
やりたいこと
Windowsの電源プランに含まれる各種設定を、プログラムから取得したい。
電源プランとは?
電源プランとは、下記の画面に出てくるもので、ノートPCやタブレットなどの電源の持ちにかかわる設定のこと。
「プラン」の中には、いろいろな設定がある。WindowsのUIで見ると、
こういうのとか、
こういうのとか。
電源プランの構成
電源プランの中身は、ざっくり下記のような階層的な作りになっている。
- 電源プラン(スキーマ(schema)とも言う)
- サブグループ
- 個別の設定
- サブグループ
それぞれ、スキーマ、サブグループ、個別の設定にはGUIDが振られていて、それを使ってコマンドやWind32APIでどれを設定するか/取得するか指定して、いろいろな操作を行う。
電源プランの設定値にはどういうものがあるか?
どういう設定があるかは、powercfg
というコマンドをコマンドプロンプトを開いてたたけば見ることができる。
https://docs.microsoft.com/ja-jp/windows-hardware/design/device-experiences/powercfg-command-line-options
powercfg -qh
と入力すると、隠し設定も含めて、現在選択しているプランに、どんな設定があるかと、その設定値を見ることができる。
(それぞれの設定には、AC電源のときの設定値と、DC電源の時の設定値がある)
ここで見える**「電源設定のGUID ・・・ (バランス)」**というのが、コントロールパネルの電源オプションの画面で見た「電源プラン」のこと。
その下に、**「サブグループ」**というグループで設定値が分けられている。
(上図の「サブグループの・・・」というのがそれ)
で、そのサブグループの中に、具体的な個別の設定値がある、というイメージ。
電源プランとそのGUIDの一覧の味方
現在選択しているプランがなにか、ということと、どんなプランがあるか、は、powercfg -l
で見ることができる。(※がついてるのが、現在選択中の電源プラン)
電源プランの中の設定値をC++で取得する
powrprof.h
にあるPowerEnumerate
関数を使って設定値を取得する。
https://docs.microsoft.com/en-us/windows/win32/api/powrprof/nf-powrprof-powerenumerate
PowerEnumerate()
は、上記MS公式解説ページを見ると下記のように定義されている。
DWORD PowerEnumerate(
HKEY RootPowerKey,
const GUID *SchemeGuid,
const GUID *SubGroupOfPowerSettingsGuid,
POWER_DATA_ACCESSOR AccessFlags,
ULONG Index,
UCHAR *Buffer,
DWORD *BufferSize
);
公式ページによると、
-
SchemeGuid
をNULLにすると、power policiesの列挙が返される。
(power policiesというのは、スキーマ(=電源プラン)のGUIDのことっぽい) -
SubGroupOfPowerSettingsGuid
をNULLにすると、個別の設定の一覧が返される。 -
Index
を++しながら何度も読んでやると、お望みの一覧が取れる
とのこと。
なので、上の階層から順番に、indexを増やしながら読んでいくと、スキーマ(電源プラン)の中のサブグループ、そのまた中に含まれる個別の設定値をぐるぐる全部取っていける様子。
それを試したのが下記。
サンプル
// include必要
#include <Windows.h>
#include <powrprof.h>
// GUIDを文字列に変換する(取得したGUIDの確認のためのデバッグ出力用)
// https://www.wabiapp.com/WabiSampleSource/windows/uuid_to_string.html
std::wstring GuidToString
(
GUID* pGuid
)
{
std::wstring oGuidString;
RPC_WSTR waString;
// GUIDを文字列へ変換する
if (RPC_S_OK == ::UuidToString(pGuid, &waString)) {
// GUIDを結果にセット
oGuidString = (WCHAR*)waString;
// GUID文字列の破棄
RpcStringFree(&waString);
}
// GUIDを返す
return(oGuidString);
}
void PowerEnumerateTest()
{
ULONG index1 = 0;
ULONG index2 = 0;
ULONG index3 = 0;
while (1)
{
UCHAR buf[256] = { 0 };
DWORD size = sizeof(buf);
GUID sheme = { 0 };
GUID subgr = { 0 };
GUID indv = { 0 };
// 電源プランのGUIDを取得
if (PowerEnumerate(NULL, NULL, NULL, ACCESS_SCHEME, index1++, buf, &size))
break;
memcpy_s(&sheme, sizeof(sheme), buf, sizeof(sheme));
OutputDebugString((GuidToString(&sheme) + L"\r\n").c_str());
index2 = 0;
while (1)
{
// サブグループのGUIDを取得
if (PowerEnumerate(NULL, &sheme, NULL, ACCESS_SUBGROUP, index2++, buf, &size))
break;
memcpy_s(&subgr, sizeof(subgr), buf, sizeof(subgr));
OutputDebugString((L" " + GuidToString(&subgr) + L"\r\n").c_str());
index3 = 0;
while (1)
{
// 個別の設定のGUIDを取得
if (PowerEnumerate(NULL, &sheme, &subgr, ACCESS_INDIVIDUAL_SETTING, index3++, buf, &size))
break;
memcpy_s(&indv, sizeof(indv), buf, sizeof(indv));
OutputDebugString((L" " + GuidToString(&indv)).c_str());
// AC/DCの設定値を取得
DWORD ac, dc = 0;
PowerReadACValueIndex(NULL, &sheme, &subgr, &indv, &ac);
PowerReadDCValueIndex(NULL, &sheme, &subgr, &indv, &dc);
OutputDebugString((L" ac:" + std::to_wstring(ac) + L" dc:" + std::to_wstring(dc) + L"\r\n").c_str());
}
}
}
}
取得した結果はこんな感じ。
381b4222-f694-41f0-9685-ff5bb260df2e
0012ee47-9041-4b5d-9b77-535fba8b1442
0b2d69d7-a2a1-449c-9680-f91c70521c60 ac:1 dc:1
51dea550-bb38-4bc4-991b-eacf37be5ec8 ac:100 dc:100
6738e2c4-e8a5-4a42-b16a-e040e769756e ac:1200 dc:600
80e3c60e-bb94-4ad8-bbe0-0d3195efc663 ac:0 dc:30
d3d55efd-c1ff-424e-9dc3-441be7833010 ac:2000 dc:1000
d639518a-e56d-4345-8af2-b9f32fb26109 ac:200 dc:100
・
・
・
取れる情報には、下記のようなものが含まれている。(他にもたくさんある)
例えば「ディスプレイの明るさ」の設定は、Windowsの設定画面の下記の値を取ってきてることになる。
色々と使えそう。
メモ
何気にはまった点。
PowerEnumerateの最後の引数BufferSize
は、PowerEnumerateを呼ぶ時点で、Bufferに必要なサイズ(GUIDなのでおそらく16)を入れておかないと、確かエラーコード234?243?が返ってきて失敗してしまうので注意。
GUID
は構造体。
参考
PowerEnumerate function (powrprof.h)
https://docs.microsoft.com/en-us/windows/win32/api/powrprof/nf-powrprof-powerenumerate
powercfgコマンド
https://docs.microsoft.com/ja-jp/windows-hardware/design/device-experiences/powercfg-command-line-options
pinvoke.net ※C#から呼ぶときのためのページ。
http://pinvoke.net/default.aspx/powrprof/PowerEnumerate.html?diff=y