2011-04-20 48 views
5

我在C#中創建了一個Windows服務來關閉計算機。創建用於關閉計算機的Windows服務在計算機被鎖定時不起作用

服務工作正常,當計算機未鎖定(Ctrl + Alt + Del)。

但有些如何當我的電腦被鎖定時不關閉。

// call 
DoExitWin(EWX_SHUTDOWN); 

[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; 

private static void DoExitWin(int flg) 
{ 
    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(flg, 0); 
} 

UPDATE:

基於幫助克里斯哈斯我試圖找到其調用返回的基礎上ok價值的錯誤:

ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
int error = Marshal.GetLastWin32Error(); //error 87 ok return true 
ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid); 
error = Marshal.GetLastWin32Error(); //error 997 ok return true rest of ok true with zero error code 

ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,IntPtr.Zero); 
ok = ExitWindowsEx(flg, 0); //This mean error in ok 

ok回報真的一直如此。

+0

服務是否在用戶帳戶下運行? – manojlds 2011-04-20 20:24:57

+0

號碼本地服務 – Rohit 2011-04-20 20:30:58

回答

2

我猜它是一個許可問題,但我不知道這一點。一個非常重要的事情是你正在拋棄潛在的錯誤。你繼續設置ok變量,但你從不檢查它。這可能會告訴你在哪裏出現了問題

編輯

另外,我覺得你真的想通過EWX_SHUTDOWN | EWX_POWEROFF

EDIT 2

如果你得到一個錯誤,你應該叫Marshal.GetLastWin32Error()

編輯3

您不必調用GetLastError每一次,只是如果ok是假的:

int error; 
ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
tp.Count = 1; 
tp.Luid = 0; 
tp.Attr = SE_PRIVILEGE_ENABLED; 
ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,IntPtr.Zero); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
ok = ExitWindowsEx(flg, 0); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
+0

不會引發任何錯誤。 WIndows服務工作正常,當電腦沒有鎖定。甚至在Windows應用程序中嘗試進行調試。 – Rohit 2011-04-20 20:29:31

+0

@Rohit,我不知道你的技術水平,所以我很抱歉,如果你已經檢查過。 Win32函數不會拋出錯誤,而是返回非零值。然後調用'GetLastError()'來確定錯誤實際是什麼。所以只是因爲你沒有得到一個例外並不意味着沒有錯誤。在每一步檢查'ok'的值,如果它的錯誤調用Marshal.GetLastWin32Error()。 – 2011-04-20 20:33:40

+0

ok = OpenProcessToken(hproc,TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,ref htok); int error = Marshal.GetLastWin32Error(); //錯誤87 ok返回true ok = LookupPrivilegeValue(null,SE_SHUTDOWN_NAME,ref tp.Luid); error = Marshal.GetLastWin32Error(); // error 997 ok return true 其餘部分正確無誤,錯誤代碼爲 – Rohit 2011-04-20 20:42:08

0

Windows服務需要安裝它的用戶帳戶的權限。你可以

編輯此權限通過右擊並選擇登錄導航到

AdministartiveTools->服務 - > yourService後。通常這會設置爲「本地服務」,

嘗試給出您的服務運行的帳戶的憑據。

Please cross check whether you have done the following steps during windows service creation: 

1.After creating the windows service project go to the service class's design view(just double click the service1.cs class). 

2.In the design view right click and select Add Installer. This will create an Installer class named ProjectInstaller.cs. With out ProjectInstaller.cs or any error in configuring ProjectInstaller.cs may result in non-showing of the service in service console. 

3.Go to the design view of ProjectInstaller.cs you will find two installers there-> 

a.**ServiceInstaller1** 

    b.**ServiceProcessInstaller1** 
4.Right click ServiceInstaller1 and go to the properties tab 

    a.Edit the ServiceName with the name you want to 
     see your service in the service console. 

    b.Change the **StartType** to **Automatic**. 
5.Right click ServiceProcessInstaller1 and go to the properties tab 

    a.Change the account to **LocalService** 

    6. Save and try it. 

希望這將幫助你........

2

改用
InitiateSystemShutdownEx。請參閱有關參數的註釋,如果機器已鎖定,則可強制關機。

編輯:我記得我前一段時間用過它。在MSDN中有一個具體的評論:

* Windows Server 2003和Windows XP:如果計算機被鎖定並且bForceAppsClosed參數爲FALSE,則上一個錯誤代碼爲ERROR_MACHINE_LOCKED。如果系統沒有準備好處理請求,則最後的錯誤代碼是ERROR_NOT_READY。應用程序應該稍等片刻,然後重試呼叫。例如,如果關閉請求在用戶嘗試登錄系統的同時發生,則系統可能不準備啓動關閉,並返回ERROR_NOT_READY。在這種情況下,應用程序應該稍等片刻,然後重試呼叫。*