一般关机用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以上的系统中,应该都可以起作用。