iooiau.net

SetSystemPowerState() の罠

SetSystemPowerState() は、システムを休止状態にする API 関数ですが、これは基本的に使ってはいけません(Windows 9x系を除く)。
なぜなら自動復帰できなくなるからです。
そうするとタスクスケジューラのスケジュールや、テレビの録画予約などが実行されないという悲しい事態になります。

代わりに SetSuspendState() という API 関数を使います。
この関数は最後の引数に DisableWakeEvent というのがあり、これを FALSE にすれば復帰のイベントが無効になりません。
SetSuspendState() は powrprof.dll 内にありますので、使う時は powrprof.lib をリンクして、powrprof.h を include します。
具体的なコードとしては以下のようになります。


#include <windows.h>
#include <powrprof.h>
#pragma comment(lib, "powrprof.lib")

BOOL Suspend(void)
{
    return SetSuspendState(FALSE, FALSE, FALSE);
}

SetSuspendState() の最初の引数を TRUE にすればハイバネートになります。

また、よく「システムを休止状態にするショートカットを作成する」などと称してこんなコマンドが掲載されていますが、


rundll32.exe PowrProf.dll,SetSuspendState

これでは自動復帰できません
理由は SetSuspendState() の引数と rundll の仕様を考えれば分かります。
そもそも rundll は 任意の API 関数を呼び出せるプログラムではありません。
rundll から呼び出す関数は以下のように定義されていなければなりません。


void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)

どう見ても SetSuspendState() とは引数が違います。
Win32 API の関数呼び出しでは最後の引数からスタックに積まれますので、こういうことになります。


SetSuspendState(hwnd, hinst, lpszCmdLine)

lpszCmdLine は NULL にはなりませんので、最後の引数が常に非0となってしまいます。

間違ったコマンドには以下のような変種もありますが、


rundll32.exe PowrProf.dll,SetSuspendState 0,1,0

これは lpszCmdLine に "0,1,0" という文字列(へのポインタ)が渡されるだけです。
0,1,0 の部分が Sleep となっていたりするものもありますが、何の意味もありません。
(この 0,1,0 や Sleep というのは、いったいどこから出てきたのでしょうか?)