【题外话】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中的代码。
【相关连接】