记得暑假的时候偶无聊写了一个MyClock的小恶作剧软件,当时用到了关机.其实之前我一直以为关机嘛,不就是ExitWindowEx就可以了嘛,其实事情没那么简单,XP下的关机需要一个提升权限(Privilege)的过程.我简单整理了一下,WindowsXP下关机至少有下面几种方法:一: 最简单的方法是 shutdown -s -t 0关于shutdown的具体用法如下:用法: shutdown [-i | -l | -s | -r | -a] [-f] [-m /computername] [-t xx] [-c "comment"] [-d up:xx:yy]没有参数 显示此消息(与 ? 相同)-i 显示 GUI 界面,必须是第一个选项-l 注销(不能与选项 -m 一起使用)-s 关闭此计算机-r 关闭并重启动此计算机-a 放弃系统关机-m /computername 远程计算机关机/重启动/放弃-t xx 设置关闭的超时为 xx 秒-c "comment" 关闭注释(最大 127 个字符)-f 强制运行的应用程序关闭而没有警告-d [p]:xx:yy 关闭原因代码 u 是用户代码 p 是一个计划的关闭代码 xx 是一个主要原因代码(小于 256 的正整数) yy 是一个次要原因代码(小于 65536 的正整数)-f:强行关闭应用程序-m /计算机名:控制远程计算机-i:显示图形用户界面,但必须是Shutdown的第一个选项-l:注销当前用户-r:关机并重启-t时间:设置关机倒计时-c "消息内容":输入关机对话框中的消息内容(不能超127个字符
(关于如何在程序中去调用我想大家已经清楚了,C/C++中可以使用system,C#里面的可以参加我写rundll32的问题)方法二: 利用ExitWindowEx这个在XP下需要有一个提升权限的过程, 我用C#写了一下:
[StructLayout(LayoutKind.Sequential, Pack = 1 )] internal struct TokPriv1Luid { public int Count; public long Luid; public int Attr; } [DllImport( " kernel32.dll " , ExactSpelling = true )] internal static extern IntPtr GetCurrentProcess(); [DllImport( " advapi32.dll " , ExactSpelling = true , SetLastError = true )] internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); [DllImport( " advapi32.dll " , SetLastError = true )] internal static extern bool LookupPrivilegeValue( string host, string name, ref long pluid); [DllImport( " advapi32.dll " , ExactSpelling = true , SetLastError = true )] internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen); [DllImport( " user32.dll " , ExactSpelling = true , SetLastError = true )] internal static extern bool ExitWindowsEx( int flg, int rea); internal const int SE_PRIVILEGE_ENABLED = 0x00000002 ; internal const int TOKEN_QUERY = 0x00000008 ; internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020 ; internal const string SE_SHUTDOWN_NAME = " SeShutdownPrivilege " ; internal const int EWX_LOGOFF = 0x00000000 ; internal const int EWX_SHUTDOWN = 0x00000001 ; internal const int EWX_REBOOT = 0x00000002 ; internal const int EWX_FORCE = 0x00000004 ; internal const int EWX_POWEROFF = 0x00000008 ; internal const int EWX_FORCEIFHUNG = 0x00000010 ;调用如下:
bool ok; TokPriv1Luid tp; IntPtr hproc = GetCurrentProcess(); IntPtr htok = IntPtr.Zero; ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); tp.Count = 1 ; tp.Luid = 0 ; tp.Attr = SE_PRIVILEGE_ENABLED; ok = LookupPrivilegeValue( null , SE_SHUTDOWN_NAME, ref tp.Luid); ok = AdjustTokenPrivileges(htok, false , ref tp, 0 , IntPtr.Zero, IntPtr.Zero); ok = ExitWindowsEx(EWX_POWEROFF, EWX_FORCE);
方法三: 使用InitiateSystemShutdown和ExitWindowEx一样, 它也需要提升权限只需将
ok = ExitWindowsEx(EWX_POWEROFF, EWX_FORCE);一句替换成
ok = InitiateSystemShutdown( null , null , 0 , false , false );别忘了加上声明:
[DllImport( " Advapi32.dll " )] internal static extern bool InitiateSystemShutdown( string lpMachineName, string lpMessage, ulong dwTimeout, bool bForceAppsClosed, bool bRebootAfterShutdown);方法四: 这个方法是最有趣的了,利用ntdll.dll里面未公开的原生API进行2s关机,无须提升权限就可以了.网上有人用IDA进行分析的文章, 有兴趣可以找找,反正我是看不懂了,- -#好了, 这里有个小插曲,就是在C#中调用这个Native API,可能水平还是不够, 在调用过程老是出错.没办法,想了一个阴招, 用VC编写dll, C#去调用, 呵呵, 最终结果不错哟!下面先建立一个Win32 DLL Project 项目,然后把下面的函数拷贝到cpp当中编译,OK,dll就出来了
#include < windows.h > extern " C " __declspec(dllexport) void ShutdownWindow1( void ) { const int SE_SHUTDOWN_PRIVILEGE = 0x13; typedef int (*RtlAdjustPrivilege)(int,bool, bool,int*); typedef int (*ZwShutdownSystem)(int); int en = 0; HMODULE module = LoadLibrary("ntdll.dll"); RtlAdjustPrivilege rtl = (RtlAdjustPrivilege)GetProcAddress(module, "RtlAdjustPrivilege"); ZwShutdownSystem shutdown = (ZwShutdownSystem)GetProcAddress(module,"ZwShutdownSystem"); int nRet=rtl(SE_SHUTDOWN_PRIVILEGE,TRUE,TRUE,&en); if(nRet==0x0C000007C) nRet = rtl(SE_SHUTDOWN_PRIVILEGE,TRUE,FALSE,&en); nRet=shutdown(2);}然后把dll拷贝到C#工程的Release/Debug的文件目录下, 加上下面的话就OK了, 2s关机, So Cool!
[DllImport( " ShutdownDll.dll " ,CallingConvention = CallingConvention.Cdecl)] public static extern void ShutdownWindow();
调用 ShutdownWindow();
