65.9K
CodeProject 正在变化。 阅读更多。
Home

执行紧急关机

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (9投票s)

2009年3月17日

CPOL

2分钟阅读

viewsIcon

53891

downloadIcon

1451

如何在紧急情况下快速关机/强制关机。

Demo_Executable

引言

有时应用程序需要快速关闭Windows。不幸的是,没有很好的文档记录的方法可以做到这一点,微软也不支持这样做。事实上,我也不支持。但是,我将介绍两种方法,仅作为一种想法。

免责声明:对于此程序的任何意外行为,我概不负责。如果您的计算机之后无法启动,那并非我的责任。该程序仅作为“概念证明”提供。

背景

Windows内核中的许多Nt/Zw函数都有文档记录,但有些没有。NtShutdownSystem函数在这里NTInternals中有很好的文档记录。但是,NtSetSystemPowerState函数没有。

在Windows关机过程的最后阶段,会调用NtShutdownSystem函数。它负责关闭所有驱动程序,刷新注册表配置单元和磁盘缓存,清除页面文件等。完成后,它会调用NtSetSystemPowerState函数。

然后,NtSetSystemPowerState会使所有即插即用设备关闭,并使系统停止运行、关闭电源或重新启动。

但是,在没有事先通知系统的情况下调用这两个函数极其危险,可能会导致系统不稳定。

使用代码

NtShutdownSystemNtSetSystemPowerState都位于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参数,该参数在这里有文档记录。三个选项ShutdownNoRebootShutdownRebootShutdownPowerOff是不言自明的。

NtSetSystemPowerState稍微复杂一些。Microsoft 通过记录所有三个参数使它更容易一些。POWER_ACTIONSYSTEM_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日。
© . All rights reserved.