C#实现以管理员身份运行程序的最全总结(WinForm/WPF)

2,197 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

程序使用过程中经常遇到需要管理员权限运行才能执行的情况,如操作注册表、系统文件或配置文件等。

以管理员权限运行程序的最简单方式,是右键程序,选择“以管理员权限运行”。

但,如果打开时,默认以系统管理员权限运行,将会很方便。本篇将对几种实现管理员权限运行的方式进行总结,希望足够全。

方法一【ClickOnce生成清单文件】

  • Visual studio中,解决方案资源管理器下,右键项目>属性,在安全性下,勾选启用ClickOnce安全设置

  • app.manifest文件会出现在项目名下面的属性目录中。

双击打开,并找到代码<requestedExecutionLevel level="asInvoker" uiAccess="false" />,将属性level的值改为requireAdministrator

文件中对UAC控制(User Account Control)已经进行了说明

修改后保存即可。

权限说明

  • asInvoker : 应用程序以当前的权限运行。
  • highestAvailable: 以当前用户可以获得的最高权限运行。
  • requireAdministrator: 请求以系统管理员权限运行。
  • 重新打开项目属性>安全性,将启用ClickOnce安全设置的勾选取消。

启用ClickOnce安全设置的情况下: 如果debug启动,程序会提示不可用于VS进程。VS将不能进行安全调试。

如果直接生成,会报错 ClickOnce 不支持请求执行级别“requireAdministrator”。 RegisterUse

因此,需要取消勾选启用ClickOnce安全设置

  • 执行 调试>启动,会提示相应权限运行。

即,要管理员权限运行当前程序,需要vs也是管理员权限打开。

  • 重新编译生成exe程序,双击运行,会请求管理员权限运行。

方法二【直接添加清单文件】

项目下添加项目清单文件。

  • 右键项目>添加>新建项>选择应用程序清单文件

  • 此时在项目下会生成app.manifest文件。其内容和修改与上面的设置相同

这样就不用修改启用ClickOnce安全设置

方法三【判断程序自身是否管理员权限运行,并使用Process管理员重新启动自身】

通过判断当前运行程序的权限是管理员还是非管理员,决定是否请求管理员权限运行程序。这对于将程序安装到C盘后,需要管理员权限操作,其他盘则不需要管理员权限,会显得比较灵活。

通过修改Program文件,借助System.Diagnostics.Process.Start()以应用程序进程的方式重新以管理员权限打开程序(只有当前用户为管理员时才会直接运行)。

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        //获取当前登陆的windows用户
        //获取当前Windows用户的WindowsIdentity对象
        System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
        //创建可以代码访问的windows组成员对象
        System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
        //判断是否为管理员
        if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
        {
            //如果是管理员则直接运行
            Application.Run(new Form1());
        }
        else
        {
            //创建启动对象
            //指定启动进程时的信息
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.UseShellExecute = true;
            startInfo.WorkingDirectory = Environment.CurrentDirectory;//设置当前工作目录的完全路径
            startInfo.FileName = Application.ExecutablePath;//获取当前执行文件的路径
            //设置启动动作,确保以管理员权限运行
            startInfo.Verb = "runas";
            try
            {
                System.Diagnostics.Process.Start(startInfo);
            }
            catch (Exception)
            {
                return;
            }
            //退出当前,使用新打开的程序
            Application.Exit();
        }

        //Application.Run(new Form1());
    }
}

方法四【修改程序属性的兼容性设置】

直接修改程序文件的属性。

右键exe文件,属性>兼容性下,设置以管理员身份运行此程序

附:判断程序当前运行是管理员权限还是非管理员权限

public static bool IsAdministrator()
{
    WindowsIdentity identity = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(identity);
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}

附:通过Process.Start()启动程序时接收命令行或输入参数

上面使用Process.Start()以管理员方式重新启动自身程序时,没有考虑到Main入口方法的输入参数的传递问题。借助ProcessStartInfo.Arguments可以在启动程序时,传入启动参数。

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] Args)
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    //获取当前登陆的windows用户
    //获取当前Windows用户的WindowsIdentity对象
    WindowsIdentity identity = WindowsIdentity.GetCurrent();
    //创建可以代码访问的windows组成员对象
    WindowsPrincipal principal = new WindowsPrincipal(identity);
    //判断是否为管理员
    if (principal.IsInRole(WindowsBuiltInRole.Administrator))
    {
        //如果是管理员则直接运行
        if (Args.Length>0)//判断是否输入参数
        {
            Application.Run(new Form1(Args));
        }
        else
        {
            Application.Run(new Form1());
        }
    }
    else
    {
        //创建启动对象
        //指定启动进程时的信息
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.UseShellExecute = true;
        startInfo.WorkingDirectory = Environment.CurrentDirectory;//设置当前工作目录的完全路径
        //设置运行文件
        startInfo.FileName = Application.ExecutablePath;//获取当前执行文件的路径
        //设置启动参数
        if (Args.Length>0)
        {
            //获取或设置启动应用程序时的邮政命令行自变量
            startInfo.Arguments = String.Join(" ", Args);
        }
        //设置启动动作,确保以管理员权限运行
        startInfo.Verb = "runas";
        try
        {
            Process.Start(startInfo);
        }
        catch (Exception)
        {
            MessageBox.Show("启动失败!");
            return;
        }
        //退出当前,使用新打开的程序
        Application.Exit();
    }
}

ProcessStartInfo.Verb = "runas"以管理员权限启动进程来说,可以实现管理员权限运行另一个程序,或,启动另一个进程。

参考