Windows关机方法

时间:2024-02-24 13:56:50

一般关机用Shutdown便已足够,在xp下运行中输入shutdown -f -s -t 0便是0秒关机。在windows 7下则也可以输入shutdown -s -p

相应的,在程序中使用这个方法,在C++中很简单

 

char buf[40];

strcpy(buf,
"shutdown -f -s -t 0");

system(buf);

在C#中也不难

 

ProcessStartInfo shutdown = new ProcessStartInfo();
shutdown.FileName
= "shutdown.exe";
shutdown.Arguments
= "-f -s -t 0";
Process.Start(shutdown);

 

 

但是这都是调用系统的关机程序来关机,那我们的进程可不可以自己关机呢?答案是肯定的。

系统关机需要若干步骤,前几步大概都是退出进程,退出用户之类的系统操作,和关机这个主题关系不大。不执行顶多损失未保存数据,但是有的时候关机本身比较重要,需要优先执行,那么就要提到windows的关闭系统的函数NtShutdownSystem();

要让自己的进程执行关机操作,首先要让自己的进程有关机的权限,系统的权限种类在MSDN的Privilege Constants中有详细叙述,具体定义在windows sdk的winNT.h文件中7806行的位置。

关机所需的权限是SeShutdownPrivilege,我们在C++中可以这样获得

 

代码
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken))
{
TOKEN_PRIVILEGES tkp;
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);
}

 

在也可以使用API来改变权限,这个例子用C#来写

 

[DllImport("ntdll.dll")]
private static extern void RtlAdjustPrivilege(int Privilege, bool Enable, bool Thread, out bool OldValue);

其中Privilege是权限的枚举值,Enable是表示开启还是关闭, Thread表示是改变当前线程权限还是改变整个进程权限,最后一个输出是原来此权限的值。

SeShutdownPrivilege的枚举值是19,那么执行如下代码就可以让此线程获得关机的能力

 

bool a;
RtlAdjustPrivilege(
19, true, false, out a);

 

 

关闭系统的话调用NtShutdownSystem即可,此函数不载于MSDN中,其描述可见MSDN未载之API,摘录如下

 

NTSYSAPI
NTSTATUS
NTAPI

NtShutdownSystem(


IN SHUTDOWN_ACTION Action );

 

 

其中Shutdown_action是一个枚举 其枚举类型为

 

enum SHUTDOWN_ACTION {



ShutdownNoReboot,
ShutdownReboot,
ShutdownPowerOff


}

 

 

相应的,调用此API的C++代码为

 

代码
DWORD (__stdcall *NtShutdownSystem)(SHUTDOWN_ACTION);
HMODULE hMod;
hMod
= LoadLibraryA("ntdll.dll");
if(hMod)
{
NtShutdownSystem
= (DWORD(__stdcall *)(SHUTDOWN_ACTION))GetProcAddress(hMod, "NtShutdownSystem");
NtShutdownSystem(ShutdownNoReboot);
}

 

C#代码为

 

[DllImport("NTDLL.dll")]
public static extern int NtShutdownSystem(SHUTDOWN_ACTION action);
NtShutdownSystem(SHUTDOWN_ACTION.ShutdownNoReboot);

NtShutdownSystem其实算比较正常的关机,毕竟还是执行了关闭硬盘,清空页面文件和缓冲区等操作,WINNT还提供一个API,可以使我们设置电源状态,这个API就是NtSetSystemPowerState

NtSetSystemPowerState这个API不载于MSDN也不载于NTInternal,但是网上仍然能找到这个API的描述,这个API是这样的

 

NTSYSAPI
NTSTATUS
NTAPI
NtSetSystemPowerState(
IN POWER_ACTION SystemAction,
IN SYSTEM_POWER_STATE MinSystemState,
IN ULONG Flags);

 

其中POWER_ACTION表示关机动作,SYSTEM_POWER_STATE表示系统电源状态,Flags则表示系统关机原因。这三者在MSDN中都有详细记载,Flags的值则在Windows SDK的Reason.h中定义。

他们的值是这样的

 

代码
enum SYSTEM_POWER_STATE {
PowerSystemUnspecified
= 0,
PowerSystemWorking
= 1,
PowerSystemSleeping1
= 2,
PowerSystemSleeping2
= 3,
PowerSystemSleeping3
= 4,
PowerSystemHibernate
= 5,
PowerSystemShutdown
= 6,
PowerSystemMaximum
= 7
}
enum POWER_ACTION {
PowerActionNone
= 0,
PowerActionReserved,
PowerActionSleep,
PowerActionHibernate,
PowerActionShutdown,
PowerActionShutdownReset,
PowerActionShutdownOff,
PowerActionWarmEject
}

 

在C#中调用NtSetSystemPowerState来关机的代码如下

 

代码
[DllImport("NTDLL.dll")]
public static extern int NtSetSystemPowerState(POWER_ACTION action, SYSTEM_POWER_STATE status, uint flag);

...

NtSetSystemPowerState(POWER_ACTION.PowerActionShutdownOff, SYSTEM_POWER_STATE.PowerSystemShutdown,
0x80000000);

 

如此便可以实现快速的关机了。但是除此之外,我想windows的关机方法还有很多,应该有更加便捷的关机方法,来为日常应用提供方便。文本中提到的关机方法,在Windows7和XP下测试通过,在2000以上的系统中,应该都可以起作用。