WinAPIを使って、アプリ起動中に
- スリープモード
- ディスプレイの自動電源OFF
- スクリーンセーバー
への移行を抑止する方法について、調べて実験した内容を書いていきます。
SetThreadExecutionState API
Win32APIのSetThreadExecutionState
APIをコールすることで、スリープモードなどの移行を抑止できます。
何をどのように抑止するかは引数で決めることができます。
// スタンバイ移行までのタイマーをリセットする // caution: 数十秒に1回ほど,繰り返し呼び出す必要がある ::SetThreadExecutionState(ES_SYSTEM_REQUIRED); // スタンバイを抑止 // memo: AppのInitInstanceなどで1度呼べばOK ::SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS); // ディスプレイ自動OFFやスクリーンセーバーの突入までのタイマーをリセットする // caution: 数十秒に1回ほど,繰り返し呼び出す必要がある ::SetThreadExecutionState(ES_DISPLAY_REQUIRED); // ディスプレイ自動OFFやスクリーンセーバーの突入を抑止 // memo: AppのInitInstanceなどで1度呼べばOK ::SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS); // 抑止を解除 ::SetThreadExecutionState(ES_CONTINUOUS);
引数
引数 | 説明 | 使いどころ |
---|---|---|
ES_SYSTEM_REQUIRED |
システムがシステムアイドルタイマをリセットして、コンピュータをスリープ状態にするのを防ぐことができる。 | 処理中などスリープしてほしくない時 |
ES_DISPLAY_REQUIRED |
ディスプレイのアイドルタイマーをリセットして、ディスプレイを強制的にオンにします。 | ビデオ再生など,長時間ユーザー操作がない状態 |
ES_CONTINUOUS |
次にES_CONTINUOUS を呼び出すまで,実行を維持する必要があることをシステムに通知する。 |
1回の呼び出しで済ませたいとき,抑制を解除するとき |
戻り値
成功 | 前のスレッド実行状態を返す |
失敗 | NULL |
注意事項
- 自動的な突入の回避は可能だが,ユーザー操作によるスリープは検知不可能
- このAPIが効かないPCがある
- アプリ終了時,抑止するアプリがいなくなったことで自動的にスリープ抑止の解除が行われるが,明示的に抑止解除のコードを明記しておいた方がお行儀がいい。
ES_DISPLAY_REQUIRED
は|ES_CONTINUOUS
とセットで使えないとの記事が多く見受けられたが,私の環境では正常に動いた。理由は調査中。
テストプログラムで実験
電源要求を確認
アプリケーションとドライバーの電源要求がないか,コマンドプロンプト(管理者権限)で以下のコマンドを打って確認します。
powercfg /requests
電源要求があると、スリープやディスプレイの自動電源OFFが働きませんので,"ない"状態で試しましょう。
テストプログラムを実行
簡単なテストプログラムを作り,自動突入を防げるか確認。
コードはGitHubに載せたので割愛します。
github.com
結果
以下のテストを行い,すべてパスした。
SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS) をコールしてシステムスリープ移行の抑止 |
OK |
SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS) をコールしてディスプレイの自動電源OFF移行の抑止 |
OK |
SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS) をコールしてスクリーンセーバー移行の抑止 |
OK |
SetThreadExecutionState(ES_SYSTEM_REQUIRED) をTimerで30秒ごとにコールしてシステムスリープ移行の抑止 |
OK |
SetThreadExecutionState(ES_DISPLAY_REQUIRED) をTimerで30秒ごとにコールしてディスプレイの自動電源OFFの抑止 |
OK |
SetThreadExecutionState(ES_DISPLAY_REQUIRED) をTimerで30秒ごとにコールしてスクリーンセーバー移行の抑止 |
OK |
SetThreadExecutionState(ES_CONTINUOUS) をコールして抑止の解除→Windowsの設定通りの動作をする |
OK |
ではまた。
written by @mogmo1012