tmori3y2のブログ

主にWindowsのプログラムなど

プログラム実行中にスリープやWindows Updateによる再起動をしないように設定するAPI

勘違いでした

tmori3y2.hatenablog.com

という記事を書きましたがガセでした。すみません・・・タイトルはもう修正済みです。

powercfg /requestsで電源要求しているプログラムをチェックするというのは正しいです。

そして、APIを使用して電源要求をしたプログラムがいる場合は、取り下げられるか、そのプログラム (スレッド)が終了するまでは、スリープなどの省電力モードやWindows Updateによるアクティブ時間外の再起動が抑制されるのも正しいです。

しかし、powercfg /requestsoverrideについては、「昼間はメディア共有のプロセスが立ち上がっていたので、たまたまスリープしなかったんじゃないか?」という疑惑が浮上。

実際、仕込みをして、dismコマンド実行中に別のコマンドプロンプトでpowercfg /requestsを実行しても、dismはスリープ阻害要因として表示されない。

結局、何がガセかというと、powercfg /requestsoverrideが電源要求を追加するコマンドではなく、明らかに処理が終わったのに居座って電源要求しているのを強制的にキャンセルする逆のコマンドだった・・・ということです。

特定のプロセス、サービス、ドライバーに対する電源要求の優先を設定します。パラメーターを指定しない場合は、現在の電源要求の優先設定の一覧が表示されます。

引数:

<CALLER_TYPE> PROCESS、SERVICE、DRIVER のいずれかの呼び出し元の種類を指定します。これを取得するには、POWERCFG /REQUESTS コマンドを呼び出します。

<NAME> 呼び出し元の名前を指定します。この名前を返すには、POWERCFG /REQUESTS コマンドを呼び出します。

<REQUEST> 次の電源要求の種類を 1 つ以上指定します。DISPLAY、SYSTEM、AWAYMODE

例:

POWERCFG /REQUESTSOVERRIDE PROCESS wmplayer.exe DISPLAY SYSTEM

この説明読んだら、電源要求を設定するって思いますよね?

wmplayerがいかにもって感じですし、設定した内容はレジストリに残り、キャンセルコマンドを実行しないと無効に出来ないので、勘違いするよね〜って言い訳しとく。

MediaCreationTool再び

試しに、MediaCreationToolを実行してpowercfg /requestsを実行してみる。

C:\WIM>powercfg /requests
DISPLAY:
なし。

SYSTEM:
[PROCESS] \Device\HarddiskVolume3\$Windows.~WS\Sources\SetupHost.exe

AWAYMODE:
なし。

実行:
なし。

PERFBOOST:
なし。

ACTIVELOCKSCREEN:
なし。

起動中に、Cドライブを見ると、$Windows.~WSというフォルダが出来ていて、その中のプログラムが電源要求をしているようだ。

なお、ドライブのパスにあるボリューム番号は、diskpartのlist volの値と一致している。

APIを叩けばいいのか?

SetThreadExecutionState function (Windows)

ちょっと調べれば、SetThreadExecutionStateで電源要求をすることができるとすぐに分かるが、問題はプロセスやスレッドが終了すると取り下げられてしまうことだ。

コンソールアプリを作成して実行しても、dismコマンドを実行するときには電源要求は消えてしまう。

ダメもとで、LinqPadとかのスクリプトは、実行環境が立ち上げっぱなしだからどうかな?と試しにP/Invokeしてみた。

<Query Kind="Program">
  <Namespace>System.Runtime.InteropServices</Namespace>
</Query>

[Flags]
enum EXECUTION_STATE : uint
{
    ES_SYSTEM_REQUIRED = 0x00000001,
    ES_DISPLAY_REQUIRED = 0x00000002,
    ES_AWAYMODE_REQUIRED = 0x00000040,
    ES_CONTINUOUS = 0x80000000,
}

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint SetThreadExecutionState(EXECUTION_STATE esFlags);

void Main()
{
    SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_AWAYMODE_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
}

LinqPadはフリー版でOKだし、管理者権限要りません。

C:\WINDOWS\system32>powercfg /requests
DISPLAY:
なし。

SYSTEM:
[PROCESS] \Device\HarddiskVolume3\Users\userx\AppData\Local\LINQPad\ProcessServer5X86B\LINQPad.UserQuery.exe

AWAYMODE:
[PROCESS] \Device\HarddiskVolume3\Users\userx\AppData\Local\LINQPad\ProcessServer5X86B\LINQPad.UserQuery.exe

実行:
[PROCESS] \Device\HarddiskVolume3\Program Files (x86)\Google\Chrome\Application\chrome.exe
WebRTC has active PeerConnections

PERFBOOST:
なし。

ACTIVELOCKSCREEN:
なし。

ちゃんと要求できていますね。

この状態で放置しても勝手に省電力モードにはならない。

ちなみに、DISPLAYをつけるとモニタも暗くならない。

問題は、dismコマンド実行時だけ電源要求したいのだけど、これはプロセス監視をするしかないんだろうなぁ・・・

以下に続く

tmori3y2.hatenablog.com