最近在設(shè)計(jì)網(wǎng)站后臺管理系統(tǒng)的時(shí)候,想到了是否可以通過頁面重啟Windows服務(wù)器
到Google搜索了一下,找到了一段似乎很普遍的代碼
事實(shí)證明,這段代碼在寫桌面應(yīng)用例如Console或者Windows Form程序的時(shí)候可以正常運(yùn)行,但是通過asp.net調(diào)用則無法通過
但是我還是把這段代碼貼出來,因?yàn)槠渲谐藗€(gè)別兩行外,其他的還是重啟服務(wù)器的必須代碼
新建一個(gè)類,在里面填入如下代碼:
首先是命名空間,調(diào)用Win API的時(shí)候,InteropServices不可少:
using System;
using System.Runtime.InteropServices;
然后是一系列的常量聲明: PRotected const int SE_PRIVILEGE_ENABLED = 0x2;
protected const int TOKEN_QUERY = 0x8;
protected const int TOKEN_ADJUST_PRIVILEGES = 0x20;
protected const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
protected const int EWX_LOGOFF = 0x0;
protected const int EWX_SHUTDOWN = 0x1;
protected const int EWX_REBOOT = 0x2;
protected const int EWX_FORCE = 0x4;
protected const int EWX_POWEROFF = 0x8;
protected const int EWX_FORCEIFHUNG = 0x10;
定義Luid結(jié)構(gòu),注意屬性: [StructLayout(LayoutKind.Sequential, Pack=1)]
protected struct LuidStruct {
public int Count;
public long Luid;
public int Attr;
}
外部非托管DLL的聲明: [DllImport("kernel32.dll", ExactSpelling=true)]
protected static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError=true)]
protected static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError=true)]
protected static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[DllImport("advapi32.dll", SetLastError=true, ExactSpelling=true)]
protected static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref LuidStruct newst, int len, IntPtr prev, IntPtr relen);
[DllImport("user32.dll", SetLastError=true, ExactSpelling=true)]
protected static extern bool ExitWindowsEx(int flg, int rea);
在NT級的操作系統(tǒng)上,需要先通知Windows系統(tǒng)即將關(guān)機(jī),并且要獲得關(guān)機(jī)的權(quán)限
以下就是關(guān)機(jī)、重啟以及注銷的實(shí)現(xiàn): protected static void DoExitWindows(int flg) {
LuidStruct tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
ExitWindowsEx(flg, 0);
}
public static void Shutdown() {
DoExitWindows(EWX_SHUTDOWN);
}
public static void Reboot() {
DoExitWindows(EWX_REBOOT | EWX_FORCE);
}
public static void Logoff() {
DoExitWindows(EWX_LOGOFF);
}
至此,重啟代碼結(jié)束,這段代碼可以很好地工作在交互環(huán)境下,也就是在用戶已經(jīng)登錄進(jìn)Windows的情況下
但是ASP.NET是運(yùn)行在非交互環(huán)境下的,查閱MSDN,在ExitWindowsEx函數(shù)定義下面發(fā)現(xiàn)這樣一段話:
The ExitWindowsEx function returns as soon as it has initiated the shutdown process. The shutdown or logoff then proceeds asynchronously. The function is designed to stop all processes in the caller's logon session. Therefore, if you are not the interactive user, the function can succeed without actually shutting down the computer. If you are not the interactive user, use the InitiateSystemShutdown or InitiateSystemShutdownEx function.
于是得到啟發(fā),發(fā)現(xiàn)非交互下重啟服務(wù)器不可以用ExitWindowsEx,需要將其替換成InitiateSystemShutdown:
[DllImport("advapi32.dll", SetLastError=true, ExactSpelling=false)]
protected static extern bool InitiateSystemShutdown(string name, string msg, int timeout, bool force, bool reboot);
參數(shù)解釋:
name:機(jī)器名,用于重啟局域網(wǎng)內(nèi)的其它機(jī)器,如果為 null 則是本機(jī)
msg:重啟消息,會(huì)顯示在重啟消息框上,在Windows 2003和XP中也會(huì)作為消息日志被保存
timeout:如果不是0,那么會(huì)顯示一個(gè)重新消息框,倒計(jì)時(shí)timeout秒后重啟
force:強(qiáng)制重啟,不等待應(yīng)用程序提示是否保存工作,對于服務(wù)器來說,應(yīng)該是true
reboot:是否是重啟,如果是false,那么做關(guān)機(jī)處理,對于服務(wù)器,應(yīng)該是true
先按照文章一開始的方法調(diào)用 AdjustTokenPrivileges 得到Privilege,然后在ASP.NET頁面里面執(zhí)行: InitiateSystemShutdown(null,null,0,true,true);
系統(tǒng)就重啟了
這里有一點(diǎn)說下,如果重啟本機(jī),那么多半會(huì)返回Service Unavailable錯(cuò)誤,這是因?yàn)樵贏SP.NET執(zhí)行結(jié)束之前系統(tǒng)已經(jīng)開始結(jié)束各個(gè)進(jìn)程了,當(dāng)然包括ASP.NET進(jìn)程,算是正常表現(xiàn),雖然看起來有些不太舒服
另外由于目前我只在自己機(jī)器上測試通過,所以沒有詳細(xì)研究權(quán)限問題,所以無法確定在一般服務(wù)器上是否可以正常運(yùn)行
初步只想到可以用權(quán)限模擬解決,即在web.config文件system.web節(jié)寫上<identity impersonate="true" userName="Administrator" passWord="pass">,不過沒有經(jīng)過確認(rèn),有時(shí)間會(huì)嘗試一下。web.config不是很安全,所以這里可能要借助于DPAPI,有點(diǎn)扯遠(yuǎn)了,就先到這里吧。
新聞熱點(diǎn)
疑難解答
圖片精選