C# 重啟計算機的問題


C# 程序重啟計算機的方法很多,網上也有不少這方面的文章,不過很多網上提供的方法在某些情況下無法獲取重啟計算機的權限導致重啟失敗。本文對這些方法做一些簡單的討論。

作者:eaglet

 

網上介紹最多的兩種方法分別是:

System.Diagnostics.Process.Start("shutdown",@"/r");

    [DllImport("user32.dll")]
        static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);

        [STAThread]
        static void Main(string[] args)
        {
            ExitWindowsEx(ExitWindows.LogOff, ShutdownReason.MajorOther & ShutdownReason.MinorOther);
            //這個語句將實現計算機注銷操作   
         }

 

這兩種方法在通常情況下工作是沒有問題的,但在某些特殊情況下,比如桌面被其它用戶鎖定時就無法重啟計算機。本人在實際工作中遇到過當當前屏幕被遠程控制軟件鎖定后,我做的后台守護進程試圖重啟計算機,結果用上述兩種方法都無法成功。分析原因,應該是遠程控制軟件用另外的帳號鎖定了屏幕(通常應該是windows service 或者 network service),這時守護進程用當前帳號重啟計算機就因為沒有權限而失敗。

要解決這個問題,我們必須要給進程賦予足夠的權限才行,於是我在調用 ExitWindowsEx 前運行了如下代碼來賦予當前進程關閉計算機權限

 

 
        //give current process SeShutdownPrivilege
        TokPriv1Luid tp;
 
        IntPtr hproc = GetCurrentProcess();
 
        IntPtr htok = IntPtr.Zero;
 
        if (!OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok))
        {
            throw new Exception("Open Process Token fail");
        }
 
        tp.Count = 1;
 
        tp.Luid = 0;
 
        tp.Attr = SE_PRIVILEGE_ENABLED;
 
        if (!LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid))
        {
            throw new Exception("Lookup Privilege Value fail");
        }
 
        if (!AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
        {
            throw new Exception("Adjust Token Privileges fail");
        }

上面代碼為當前進程賦予了關閉計算機的權限。這里需要注意的是上述代碼要執行成功同樣需要足夠的權限,通常當前進程需要以擁有至少是系統管理員權限的賬戶運行。如果沒有足夠權限,需要用程序模擬系統管理員權限,模擬其它帳號權限的問題不在本文討論范圍內。

加上如上代碼后,在其他用戶鎖定機器后,重啟計算機成功。

下面給出完整代碼

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
 
public class ExitWindows
{
    #region win32 api
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
    private struct TokPriv1Luid
    {
 
        public int Count;
 
        public long Luid;
 
        public int Attr;
 
    }
 
    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern IntPtr GetCurrentProcess();
 
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
 
    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
 
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
        ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
 
    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool ExitWindowsEx(int flg, int rea);
 
    #endregion
 
    private const int SE_PRIVILEGE_ENABLED = 0x00000002;
 
    private const int TOKEN_QUERY = 0x00000008;
 
    private const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
 
    private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
 
    #region Exit Windows Flags
    private const int EWX_LOGOFF = 0x00000000;
 
    private const int EWX_SHUTDOWN = 0x00000001;
 
    private const int EWX_REBOOT = 0x00000002;
 
    private const int EWX_FORCE = 0x00000004;
 
    private const int EWX_POWEROFF = 0x00000008;
 
    private const int EWX_FORCEIFHUNG = 0x00000010;
 
    #endregion
    
    public static void DoExitWin(int flg)
    {
 
        //give current process SeShutdownPrivilege
        TokPriv1Luid tp;
 
        IntPtr hproc = GetCurrentProcess();
 
        IntPtr htok = IntPtr.Zero;
 
        if (!OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok))
        {
            throw new Exception("Open Process Token fail");
        }
 
        tp.Count = 1;
 
        tp.Luid = 0;
 
        tp.Attr = SE_PRIVILEGE_ENABLED;
 
        if (!LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid))
        {
            throw new Exception("Lookup Privilege Value fail");
        }
 
        if (!AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
        {
            throw new Exception("Adjust Token Privileges fail");
        }
 
        //Exit windows
        if (!ExitWindowsEx(flg, 0))
        {
            throw new Exception("Exit Windows fail");
        }
    }
 
    /// <summary>
    /// Reboot computer
    /// </summary>
    /// <param name="force">force reboot</param>
    public static void Reboot(bool force)
    {
        if (force)
        {
            DoExitWin(EWX_REBOOT | EWX_FORCE);
        }
        else
        {
            DoExitWin(EWX_REBOOT | EWX_FORCEIFHUNG);
        }
    }
 
    /// <summary>
    /// Reboot computer force if hung
    /// </summary>
    public static void Reboot()
    {
        Reboot(false);
    }
 
    /// <summary>
    /// Shut down computer
    /// </summary>
    /// <param name="force">force shut down</param>
    public static void Shutdown(bool force)
    {
        if (force)
        {
            DoExitWin(EWX_SHUTDOWN | EWX_FORCE);
        }
        else
        {
            DoExitWin(EWX_SHUTDOWN | EWX_FORCEIFHUNG);
        }
    }
 
    /// <summary>
    /// Shut down computer force if hung
    /// </summary>
    public static void Shutdown()
    {
        Shutdown(false);
    }
 
    /// <summary>
    /// Log off
    /// </summary>
    /// <param name="force">force logoff</param>
    public static void Logoff(bool force)
    {
        if (force)
        {
            DoExitWin(EWX_LOGOFF | EWX_FORCE);
        }
        else
        {
            DoExitWin(EWX_LOGOFF | EWX_FORCEIFHUNG);
        }
    }
 
    /// <summary>
    /// logoff computer force if hung
    /// </summary>
    public static void Logoff()
    {
        Logoff(false);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM