天天看點

.NET中提升UAC權限的方法總結

從Vista開始,由于增加了UAC(使用者賬戶控制,User Account Control)功能,使得普通使用者不再是能控制整個電腦的超級管理者了,是以在調用很多比較重要的功能時需要提升權限來實作。有時候寫的程式需要調用這種權限,那麼大概就是分為運作前就提升以及運作後再提升兩種,在這裡整理如下。

【題外話】

從Vista開始,由于增加了UAC(使用者賬戶控制,User Account Control)功能,使得管理者使用者平時不再擁有能控制所有功能的管理者權限了,是以在調用很多比較重要的功能時需要提升權限來實作。有時候寫的程式需要調用這種權限,那麼大概就是分為運作前就提升以及運作後再提升兩種,在這裡整理如下。

【文章索引】

  1. 程式運作前提升權限
  2. 程式運作後提升權限
  3. 程式中判斷目前權限

【一、程式運作前提升權限】

如果整個程式都需要使用管理者權限的話(甚至主界面上顯示的内容都需要管理者權限才行),那麼可以讓程式一運作時就提升管理者權限,就如同大部分的安裝程式一樣。程式運作時提高權限通常采用設定manifest檔案的方式,可以在項目中添加“應用程式清單檔案”,添加完成後會生成如下圖所示的一個檔案。除此之外,也可以通過選擇項目屬性,然後進入“安全性”頁籤,然後選擇“啟用 ClickOnce 安全設定”後也會在項目的“Properties”目錄下生成app.manifest檔案。

.NET中提升UAC權限的方法總結

在注釋中很明确的說明了如果要在程式中如果需要更高的權限需要修改哪部分,不過非常好奇,這段注釋并沒有說明應該修改成哪種方式。

在http://blogs.msdn.com/b/winsdk/archive/2010/05/31/dealing-with-administrator-and-standard-user-s-context.aspx搜尋到了這兩者的差別,差別如下:

Possible requested execution level values

Value Description Comment
asInvoker The application runs with the same access token as the parent process. Recommended for standard user applications. Do refractoring with internal elevation points, as per the guidance provided earlier in this document.
highestAvailable The application runs with the highest privileges the current user can obtain. Recommended for mixed-mode applications. Plan to refractor the application in a future release.
requireAdministrator The application runs only for administrators and requires that the application be launched with the full access token of an administrator. Recommended for administrator only applications. Internal elevation points are not needed. The application is already running elevated.

差別即是,highestAvailable按目前賬号能擷取到的權限執行,而requireAdministrator則是以具有完整權限的管理者運作。如果目前賬戶是管理者賬戶的話,那麼兩者都是可以的通過提升權限來擷取到管理者權限的;而如果目前賬戶是Guest的話,那麼highestAvailable則放棄提升權限而直接運作,而requireAdministrator則允許輸入其他管理者賬戶的密碼來提升權限。

.NET中提升UAC權限的方法總結

其中App1使用的是highestAvailable,而App2則使用的是requireAdministrator,可以看出在Administrator使用者下都需要提升權限來運作,在關閉UAC的時候都不需要提升權限。而比如在Guest下highestAvailable放棄了提升權限,同時如果使用requireAdministrator的話則會提示類似下圖的輸入其他管理者賬戶密碼的對話框:

.NET中提升UAC權限的方法總結

是以,如果一個程式必須要求管理者權限才能執行或者才能執行得有意義(比如主界面上的資訊需要管理者權限才能顯示之類的),那麼不妨設定為requireAdministrator,即使使用Guest登陸的話也需要提升管理者權限;否則也可設定為highestAvaliable。

【二、程式運作後提升權限】

如果程式預設不需要權限就能運作大部分功能,隻是在個别功能上需要管理者權限的話,那麼可以采用程式運作後,當使用者需要提升權限的時候再提升權限重新運作程式。由于權限是按程序來的,是以如果需要提升整個程式的權限,隻能以管理者權限建立程序以後再結束本程式,或者以管理者權限運作其他程式或者程式通過不同參數來執行不同功能。以管理者權限執行程式其實非常簡單,隻要将ProcessStartInfo對象的Verb屬性設定為“runas”即可,例如如下的代碼即可以管理者權限重新開機本程式。

1 ProcessStartInfo psi = new ProcessStartInfo();
 2 psi.FileName = Application.ExecutablePath;
 3 psi.Verb = "runas";
 4 
 5 try
 6 {
 7     Process.Start(psi);
 8     Application.Exit();
 9 }
10 catch (Exception eee)
11 {
12     MessageBox.Show(eee.Message);
13 }      

當然,運作其他程式也是一樣的。

除此之外,我們可能還需要在這個按鈕或菜單上繪制UAC盾牌的圖示,其實系統已經提供了這樣的方法。

1 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
2 public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);
3 
4 public const UInt32 BCM_SETSHIELD = 0x160C;      

調用的時候隻要将按鈕的FlatStyle設定為System,然後采用如下的代碼就可以了,最後一項如果設為0的話則會取消顯示UAC的盾牌圖示。

1 SendMessage(button1.Handle, BCM_SETSHIELD, 0, (IntPtr)1);      

不過如果要往菜單上或者WPF的Button上繪制UAC盾牌的圖示就沒法這樣去做了,不過好在我們還可以擷取到系統圖示,不嫌棄的話可以用.NET自帶的System.Drawing.SystemIcons.Shield,其實好多軟體用的就是這個圖示,原圖如下(32×32):

.NET中提升UAC權限的方法總結

當然,也可以通過DllImport的方式從系統中擷取系統内置的圖示,其中UAC盾牌的圖示的ID是77,代碼如下。

1 [DllImport("shell32.dll", SetLastError = false)]
 2 public static extern Int32 SHGetStockIconInfo(SHSTOCKICONID siid, SHGSI uFlags, ref SHSTOCKICONINFO psii);
 3 
 4 public enum SHSTOCKICONID : uint
 5 {
 6     SIID_SHIELD = 77
 7 }
 8 
 9 [Flags]
10 public enum SHGSI : uint
11 {
12     SHGSI_ICON = 0x000000100,
13     SHGSI_SMALLICON = 0x000000001
14 }
15 
16 [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
17 public struct SHSTOCKICONINFO
18 {
19     public UInt32 cbSize;
20     public IntPtr hIcon;
21     public Int32 iSysIconIndex;
22     public Int32 iIcon;
23 
24     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
25     public string szPath;
26 }      

然後如下調用就可以将UAC盾牌的圖示設定到菜單上了:

1 SHSTOCKICONINFO iconInfo = new SHSTOCKICONINFO();
2 iconInfo.cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(iconInfo);
3 SHGetStockIconInfo(SHSTOCKICONID.SIID_SHIELD, SHGSI.SHGSI_ICON | SHGSI.SHGSI_SMALLICON, ref iconInfo);
4 Icon icon = Icon.FromHandle(iconInfo.hIcon);
5 
6 menu.Image = icon.ToBitmap();      

圖中menu1是使用的System.Drawing.SystemIcons.Shield,menu2使用的通過shell32.dll擷取到的圖示,button1是使用的SendMessage直接顯示的UAC的圖示。

.NET中提升UAC權限的方法總結

當然,還是應該判斷一下系統的版本的,確定系統是Vista及以後的版本,否則就不需要提升權限了。判斷是否是Vista隻需要判斷系統主版本号是否大于等于6就可以了,例如以下的代碼。

1 Boolean afterVista = (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 6);      

【三、程式中判斷目前權限】

如果要判斷目前是否以管理者身份運作,隻需引用“System.Security.Principal”這個命名空間,然後就可以通過如下的代碼擷取目前是否以管理者在運作。

1 WindowsIdentity identity = WindowsIdentity.GetCurrent();
2 WindowsPrincipal principal = new WindowsPrincipal(identity);
3 Boolean isRunasAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);      

除了擷取目前是否是以管理者運作,還可以通過DllImport的方式擷取到目前使用者是否是管理者使用者以及目前程序是否提升了權限(僅限Vista及以上的版本)等等,詳情可以見相關連結2中的代碼。

【相關連結】

  1. 編寫C#程式讓其在Win7 下以管理者權限運作:http://www.cr173.com/html/11557_1.html
  2. UAC self-elevation (CSUACSelfElevation):http://code.msdn.microsoft.com/windowsdesktop/CSUACSelfElevation-644673d3
  3. How to add an uac shield icon to a MenuItem:http://www.peschuster.de/2011/12/how-to-add-an-uac-shield-icon-to-a-menuitem/

如果您覺得本文對您有所幫助,不妨點選下方的“推薦”按鈕來支援我!

本文及文章中代碼均基于“署名-非商業性使用-相同方式共享 3.0”,文章歡迎轉載,但請您務必注明文章的作者和出處連結,如有疑問請私信我聯系!