问题 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。
在低得多的级别上,可以尝试挂钩 API 函数,例如 NTShutdown 甚至 NtSetSystemPowerState,这显然是“在任何类型的重新启动期间调用的最后一件事”。但我强烈建议不要尝试这个。
也就是说,有一些方法可以真正强烈地坚持不应该关闭系统。考虑以下:
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,它在某些时候(仍然可能)曾经非常像使用中止标志调用 shutdown.exe。
你的旅费可能会改变。