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

【文章索引】

  1. 程序運行前提升權限
  2. 程序運行後提升權限
  3. 程序中判斷當前權限

【一、程序運行前提升權限】

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

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

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則允許輸入其他管理員賬戶的密碼來提升權限。

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

所以,如果一個程序必須要求管理員權限才能執行或者才能執行得有意義(比如主界面上的信息需要管理員權限才能顯示之類的),那麼不妨設置爲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):

當然,也可以通過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的圖標。

當然,還是應該判斷一下系統的版本的,確保系統是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中的代碼。

發佈了27 篇原創文章 · 獲贊 26 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章