执行紧急关机
如何在紧急情况下快速关机/强制关机。
引言
有时应用程序需要快速关闭Windows。不幸的是,没有很好的文档记录的方法可以做到这一点,微软也不支持这样做。事实上,我也不支持。但是,我将介绍两种方法,仅作为一种想法。
免责声明:对于此程序的任何意外行为,我概不负责。如果您的计算机之后无法启动,那并非我的责任。该程序仅作为“概念证明”提供。
背景
Windows内核中的许多Nt/Zw函数都有文档记录,但有些没有。NtShutdownSystem
函数在这里的NTInternals中有很好的文档记录。但是,NtSetSystemPowerState
函数没有。
在Windows关机过程的最后阶段,会调用NtShutdownSystem
函数。它负责关闭所有驱动程序,刷新注册表配置单元和磁盘缓存,清除页面文件等。完成后,它会调用NtSetSystemPowerState
函数。
然后,NtSetSystemPowerState
会使所有即插即用设备关闭,并使系统停止运行、关闭电源或重新启动。
但是,在没有事先通知系统的情况下调用这两个函数极其危险,可能会导致系统不稳定。
使用代码
NtShutdownSystem
和NtSetSystemPowerState
都位于NTDLL.DLL中,这就是为什么我们必须先加载它的原因。我们还必须启用SE_SHUTDOWN_NAME
权限才能调用它。
OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hToken);
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0);
CloseHandle(hToken);
hNTDLL = LoadLibrary("NTDLL.DLL");
完成此操作后,我们获取这些函数。
typedef DWORD (WINAPI* lpNtShutdownSystem)(SHUTDOWN_ACTION Action);
lpNtShutdownSystem NtShutdownSystem =
(lpNtShutdownSystem)GetProcAddress(hNTDLL, "NtShutdownSystem");
typedef DWORD (WINAPI* lpNtSetSystemPowerState)(
IN POWER_ACTION SystemAction,IN SYSTEM_POWER_STATE MinSystemState,IN ULONG Flags);
lpNtSetSystemPowerState NtSetSystemPowerState =
(lpNtSetSystemPowerState)GetProcAddress(hNTDLL, "NtSetSystemPowerState");
如typedef
所示,NtShutdownSystem
需要一个SHUTDOWN_ACTION
参数,该参数在这里有文档记录。三个选项ShutdownNoReboot
、ShutdownReboot
和ShutdownPowerOff
是不言自明的。
NtSetSystemPowerState
稍微复杂一些。Microsoft 通过记录所有三个参数使它更容易一些。POWER_ACTION
和SYSTEM_POWER_STATE
这两个参数都有很好的文档记录。第三个参数flags
只是关机的理由,在MSDN上的这里也有文档记录。
调用实际函数相当简单。
void CEmergency_ShutdownDlg::OnShutdown() { if (NtShutdownSystem) { DWORD returnval = NtShutdownSystem(ShutdownPowerOff); if (returnval != 0) FormatNtMessage(returnval); } } void CEmergency_ShutdownDlg::OnPowerdown() { if (NtSetSystemPowerState) { DWORD returnval = NtSetSystemPowerState( PowerActionShutdownOff, PowerSystemShutdown, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED ); if (returnval != 0) FormatNtMessage(returnval); } }
FormatNtMessage
只是一个专门的函数,用于显示错误,给定一个NTSTATUS
错误代码。它使用FormatMessage
函数。
关注点
只有一个需要注意的地方:在执行任何一个函数之前,请保存所有未保存的工作,否则它们会发生一些有趣的事情。
历史
除非代码中存在严重缺陷,否则我可能不会更新它。
- v1.0 - 2009年3月16日。