質問2:「このシャットダウン状態をプログラムでキャンセルする方法はありますか?」
簡単に言えば、答えは実際にはありません。また、プログラムでシャットダウンを実際に停止する必要もありません。シャットダウンすると、深刻なデータ損失が発生したり、後続のシステム起動時のユーザーエクスペリエンスに大きな影響を及ぼしたりします。しかし、ほんの一例を挙げると、コンピューターが過熱していると想像してください。プログラムでシャットダウンを停止すると、システムが炒められる可能性があります(そして非常にイライラするユーザー)。
監視する必要があるのは、システムのシャットダウンだけではありません。休止状態および一時停止イベントもあります(WM_POWERBROADCASTメッセージを参照してください)。
とは言うものの、Windowsは、システムのシャットダウンを検出するための多数のメカニズムを提供します。例えば:
アプリケーションにメッセージポンプがある場合、Windowsが実行中のアプリケーションをポーリングしてWM_QUERYENDSESSIONに投票するときに、FALSEを返すように選択できますが 、Vista以降のWindowsは、タイムアウト後も強制的にシャットダウンします。Vista以降では、WM_QUERYENDSESSIONにfalseを返した後、ShutdownBlockReasonCreateを実行できます(実行する必要があります) 。
アプリケーションがサービスとして実行されている場合は、RegisterServiceCtrHandlerExを使用してからSetServiceStatusを使用し、SERVICE_ACCEPT_PRESHUTDOWNを設定して3分間のシャットダウン拡張機能を取得します。これにより、SERVICE_CONTROL_PRESHUTDOWN通知が送信されます。当然、サービスはログオフの影響を受けないため、ログオフ通知は受信されません。Pre-Vistaでは、SERVICE_CONTROL_SHUTDOWN通知に登録できます。
コンソールアプリケーション(およびGUIアプリも同様ですが、意味がありません)は、SetConsoleCtrlHandlerを使用して、CTRL_LOGOFFおよびCTRL_SHUTDOWN_EVENTの通知を受け取ることができます。
はるかに低いレベルでは、NTShutdownやNtSetSystemPowerStateなどのAPI関数をフックしてみることができます。これは、明らかに「あらゆるタイプの再起動中に呼び出される最後のもの」です。しかし、私はこれを試みないことを強くお勧めします。
とはいえ、システムをシャットダウンしてはならないことを強く主張する方法があります。次のことを考慮してください。
1.)シャットダウン通知を受信するためにアプリケーションを最初に登録してみてください。何かのようなもの:
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686227(v=vs.85).aspx
if(!SetProcessShutdownParameters(0x4ff, 0)) // greedy highest documented System reserved FirstShutdown
{
// Fallback
if(!SetProcessShutdownParameters(0x3ff, 0)) // highest notification range for applications
{
// shouldn't happen
}
}
2.)WM_QUERYENDSESSIONでFALSEを返します。Vista以降、WM_QUERYENDSESSIONでfalseを返した後、ShutdownBlockReasonCreate()を呼び出します。
3.)システムを稼働状態に保ち、使用可能にする必要があることをWindowsに通知します。http://msdn.microsoft.com/en-us/library/windows/desktop/aa373208(v=vs.85).aspxを
ご覧ください
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
4.)クリーンアップし、Vista以降でShutdownBlockReasonDestroy()を呼び出してから、システムをクリーンにシャットダウンします。
文書化されていない関数を試すこともできます(少なくともMSDNにはありません)。 "user32.dll"のCancelShutdownは、ある時点で(まだ)、abortフラグを指定してshutdown.exeを呼び出すのと非常によく似た機能を果たしていました。
あなたのマイレージは異なる場合があります。