【題外話】html
從Vista開始,因爲增長了UAC(用戶帳戶控制,User Account Control)功能,使得管理員用戶平時再也不擁有能控制全部功能的管理員權限了,因此在調用不少比較重要的功能時須要提高權限來實現。有時候寫的程序須要調用這種權限,那麼大概就是分爲運行前就提高以及運行後再提高兩種,在這裏整理以下。shell
【文章索引】windows
若是整個程序都須要使用管理員權限的話(甚至主界面上顯示的內容都須要管理員權限才行),那麼可讓程序一運行時就提高管理員權限,就如同大部分的安裝程序同樣。程序運行時提升權限一般採用設置manifest文件的方式,能夠在項目中添加「應用程序清單文件」,添加完成後會生成以下圖所示的一個文件。除此以外,也能夠經過選擇項目屬性,而後進入「安全性」選項卡,而後選擇「啓用 ClickOnce 安全設置」後也會在項目的「Properties」目錄下生成app.manifest文件。app
在註釋中很明確的說明了若是要在程序中若是須要更高的權限須要修改哪部分,不過很是好奇,這段註釋並無說明應該修改爲哪一種方式。ide
在http://blogs.msdn.com/b/winsdk/archive/2010/05/31/dealing-with-administrator-and-standard-user-s-context.aspx搜索到了這二者的區別,區別以下:ui
Possible requested execution level valuesthis
Valuespa |
Description3d |
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。
【2、程序運行後提高權限】
若是程序默認不須要權限就能運行大部分功能,只是在個別功能上須要管理員權限的話,那麼能夠採用程序運行後,當用戶須要提高權限的時候再提高權限從新運行程序。因爲權限是按進程來的,因此若是須要提高整個程序的權限,只能以管理員權限建立進程之後再結束本程序,或者以管理員權限運行其餘程序或者程序經過不一樣參數來執行不一樣功能。以管理員權限執行程序其實很是簡單,只要將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中的代碼。
【相關連接】