トップレベルウィンドウを持つスレッドから SetSuspendState を呼び出した場合スリープ状態に入るまで時間がかかる

現象

トップレベルウィンドウを所有するスレッドから SetSuspendState を呼び出した場合、トップレベルウィンドウを所有しないスレッドから呼び出した場合よりもスリープ状態へ移行するまで時間がかかります。

原因

システムの電源状態が変わる場合、Windows は全てのトップレベルウィンドウに対して WM_POWERBROADCAST メッセージをブロードキャストして変更を通知します。WM_POWERBROADCAST メッセージは SetSuspendStateを呼び出したスレッドからではなく、システムの csrss.exe プロセスから送信されます。Windows は各トップレベルウィンドウに対してメッセージに応答する時間を最大 2 秒与えます。しかしトップレベルウィンドウを持つスレッドのメッセージポンプが停止している場合、応答を返すことができず、タイムアウトまで待機する状態が発生します。

トップレベルウィンドウを持つスレッドから SetSuspendState を呼び出した場合、SetSuspendState を呼び出したスレッドは、この処理が返るまでメッセージポンプが停止状態になるため、システムから送られてきたメッセージに応答することができません。このため、トップレベルウィンドウを持たないスレッドから SetSuspendState を呼び出した場合よりもスリープ状態へ移行する時間がかかります。

解決方法

SetSuspendState を Windows アプリケーションから呼び出す場合、トップレベルウィンドウを持たないスレッドから呼び出します。対応策の一つとして、SetSuspendState を呼び出す専用のスレッドを作成する方法があります。

詳細

可視、不可視を含む全てのトップレベルウィンドウは、ブロードキャストされたウィンドウ メッセージを受け取ります。スレッドが直接トップレベルウィンドウを作成しなくても、内部的に作成されて所有する場合があります。例えば COM オブジェクトを OleInitialize、 CoInitialize または CoInitializeEx (COINIT_SINGLETHREADED) からシングル スレッド アパートメント (STA) で作成した場合、不可視のトップレベルウィンドウが作成されます。

.NET アプリケーションから Application.SetSuspendState メソッドを呼び出す場合、トップレベルウィンドウを所有しない、そして STAThread 属性を持たないスレッドから呼び出すようにします。

また、Windowsの既存のユーザーインターフェースからの操作によるスリープ (チャーム -> 設定 -> 電源 -> スリープ)処理は、SetSuspendState の呼び出しをトップレベルウィンドウを持たないスレッドから実行しています。このため遅延は発生しません。
プロパティ

文書番号:3007180 - 最終更新日: 2016/09/29 - リビジョン: 1

フィードバック