Windowsでプログラムを実行しているとたまに困るのが、スクリーンセーバーの起動やモニターの電源の自動OFF、または、スタンバイモードへの移行だ。

そこで、これらを抑止する方法を調べたので以下、メモ。
一応、WindowsAPIでの実装の仕方の説明と、実際に(MFCで)実装したプログラムを掲載する。

スタンバイモードへの移行抑制

まず、これは、これはそんなに難しくない。
Win32APIにはSetThreadExecutionState()APIがある。
これを単純に、定期的に
::SetThreadExecutionState(ES_SYSTEM_REQUIRED);等と呼び出せばよい。

これは「このプログラムは、スタンバイなどになると困りますよ」とWindowsに通知し、Windowsは、スタンバイへ行するためのタイマーを0にリセットする。

ただ、これだと数十秒程度に1回、このAPIを呼ぶ必要があるので面倒だ。
そこで、このAPIはこう言う呼び方も出来る:
::SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
これを1回呼ぶだけで、このプログラムが起動中にはスタンバイへの移行は行われなくなる。

なお、スタンバイへの移行抑止を解除する場合には次のようにすればよい。
::SetThreadExecutionState(ES_CONTINUOUS);

スクリーンセーバーや、モニター電源OFFの抑制

さっきの::SetThreadExecutionState()APIを見ると
::SetThreadExecutionState(ES_SYSTEM_ES_DISPLAY_REQUIRED);という引数もある。

これは「このプログラムは、画面を使っているので画面を消さないでね」とWindowsに通知することで、スクリーンセーバーや、モニター電源OFFの抑制するための命令だ。

ただ、先の、ES_SYSTEM_REQUIREDと違うのは、こちらはES_CONTINUOUSが使えない点。
つまり、WindowsTimer等を使って、定期的にこのAPIを呼ぶ必要がある点だ。

さらに話をややこしくしているのが、WindowsVista以降では、このAPIを呼ぶだけでは、スクリーンセーバーの抑止にはならない点だ。
※モニターの電源OFFの抑止にはなる。

では、どのようにしてスクリーンセーバーの抑止をすればいいのかというと、何のことはない、マウスを動かせば良いのである。

とはいっても、WM_MOUSE_MOVE等をPOSTしたりしても意味がない。
もっと、低レベルなところでマウスを動かす必要があり、たとえば、SendInput()APIを使うと良いだろう。

というわけで、具体例だ。
//スクリーンセーバーカウンターをリセット
::SetThreadExecutionState(ES_DISPLAY_REQUIRED);
//マウスを動かして、スクリーンセーバー抑止
INPUT input[1];
::ZeroMemory(input, sizeof(INPUT));
input[0].type = INPUT_MOUSE;
input[0].mi.dwFlags = MOUSEEVENTF_MOVE;//相対座標指定でマウスを動かす。
input[0].mi.dx = 0; //でも0で初期化しているので相対座標0で動かさない。
input[0].mi.dy = 0;
::SendInput(1, input, sizeof(INPUT)); //移動
このコードでは、
SetThreadExecutionState()APIの他に、
マウスを、現在の座標から(0,0)移動させている。
※つまり、実質的には移動しない。

これを、30秒に1回程度呼び出せば、スクリーンセーバーと、モニター電源OFFの抑止になる。

30秒というのは、スクリーンセーバーなどへの移行の最小単位が1分なので、それより少なければ、大丈夫なはずだ。

実際のプログラム

というわけで、これらの処理を入れたプログラムがこちら:
SleepStopper Ver0.1
(MD5)E6389DCAE30CA01D8FDE37F4C89F0B0C
(SHA-1)B71236F7B8EC15BEDE0B855BB06F733EB2A49800

んで、ソースコードがこちら:
SleepStopper Ver.0.1 ソース
(MD5)7AC98B342357162F49EA8233C4859F5E
(SHA-1)7FBDC5850E035E3AB667F8919FFE5362C8AB3325

以上、参考になれば。