Запуск приложения от имени администратора с технологией ClickOnce

Сегодня мы рассмотрим способ, который позволит приложению ClickOnce запускаться от имени администратора. Дело в том, что если мы воспользуемся обычной правкой манифеста <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />, то программа не скомпилируется и выдаст ошибку: «ClickOnce не поддерживает уровень выполнения запроса «requireAdministrator»». Чтобы реализовать запуск программы от имени администратора и, при этом, продолжить использовать ClickOnce, мы будем манипулировать процессами при старте программы. В статье описан способ как для Windows Forms, так и для WPF.

Windows Forms

Для начала создадим новое приложение Windows Forms и откроем файл Program.cs. В первую очередь отметим все необходимые пространства:

using System;
using System.Windows.Forms;
using System.Security.Principal;
using System.Diagnostics;
using System.Reflection;

Теперь напишем метод проверки прав администратора:

/// <summary>
/// Проверка прав администратора
/// </summary>
/// <returns></returns>
bool IsRunningAsAdmin()
{
    //Получим пользователя
    WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
    //Получим роль
    WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
    //Вернём ТРУ, если приложение имеет права администратора
    return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
}

Дальше будет самое интересное. Перед стартом приложения мы будем проверять права админа и, если их нет, то запускаем копию процесса, но уже от имени администратора, а первый процесс убиваем:

//Если программа запускается НЕ от имени администратора
if (!IsRunningAsAdmin())
{
    //Настройка информации о новом процессе нашего приложения
    ProcessStartInfo processStartInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase);
    //Настройка ProcessStartInfo. Ключевое слово «runas» позволит запустить процесс от имени администратора
    processStartInfo.UseShellExecute = true;
    processStartInfo.Verb = "runas";
    //Запуск нового процесса нашего приложения
    try {
        Process.Start(processStartInfo);
    }
    catch {
        Application.Exit();
    };

    //Остановка старого процесса
    Application.Exit();

}
else
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

Такой способ позволит принудительно запускать приложение от имени администратора, ClickOnce Ругаться не будет. Можно дать пользователю возможность выбора. Перед запуском приложения спросим юзера как именно будем выполнять программу. Код Program.cs:

using System;
using System.Windows.Forms;
using System.Security.Principal;
using System.Diagnostics;
using System.Reflection;

namespace WindowsFormsApp1
{
    static class Program
    {
        /// <summary>
        /// Главная точка входа для приложения.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // Если запуск НЕ от имени администратора
            if (!IsRunningAsAdmin())
            {
                //Спросим нужно ли использовать права админа
                DialogResult result = MessageBox.Show(
                    "Запустить программу от имени администратора?",
                    "Запуск от имени администратора",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question);
                if(result == DialogResult.Yes)
                {
                    // Настройка информации о новом процессе нашего приложения
                    ProcessStartInfo processStartInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase);
                    // Настройка ProcessStartInfo. Ключевое слово «runas» позволит запустить процесс от имени администратора
                    processStartInfo.UseShellExecute = true;
                    processStartInfo.Verb = "runas";

                    // Запуск нового процесса нашего приложения
                    try
                    {
                        Process.Start(processStartInfo);
                    }
                    catch
                    {
                        Application.Exit();
                    };

                    // Остановка старого процесса
                    Application.Exit();
                }
                else
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }


            /// <summary>
            /// Проверка прав администратора
            /// </summary>
            bool IsRunningAsAdmin()
            {
                //Получим пользователя
                WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
                //Получим роль
                WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
                //Вернём ТРУ, если приложение имеет права администратора
                return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
            }
        }
    }
}

Пример работы вышеуказанного кода:

Теперь если нажмем «Да», то увидим стандартное предупреждение UAC и запустим программу от имени администратора, Если нажмём «Нет», приложение запустится в обычном режиме.

WPF

Для реализации функционала запуска WPF-приложения с ClickOnce от имени администратора, создадим новый проект и в файле App.xaml удалим атрибут StartupUri. Код должен стать таким:

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
    </Application.Resources>
</Application>

Далее откроем App.xaml.cs и укажем необходимые пространства имен:

using System;
using System.Windows;
using System.Security.Principal;
using System.Diagnostics;
using System.Reflection;

Здесь же напишем метод проверяющий права администратора:

/// <summary>
/// Проверка прав администратора
/// </summary>
/// <returns></returns>
bool IsRunningAsAdmin()
{
    //Получим пользователя
    WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
    //Получим роль
    WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
    //Вернём ТРУ, если приложение имеет права администратора
    return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
}

Теперь мы  мы проверяем, запущен ли процесс от имени администратора. Если это нет, то перезапускаем текущий процесс в режиме администратора:

//Переопределяем метод OnStartup
protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    //Если программа запускается НЕ от имени администратора
    if (!IsRunningAsAdmin())
    {
        //Настройка информации о новом процессе нашего приложения
        ProcessStartInfo processStartInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase);
        //Настройка ProcessStartInfo. Ключевое слово «runas» позволит запустить процесс от имени администратора
        processStartInfo.UseShellExecute = true;
        processStartInfo.Verb = "runas";
        //Запуск нового процесса нашего приложения
        try
        {
            Process.Start(processStartInfo);
        }
        catch
        {
            Current.Shutdown();
        };

        //Остановка старого процесса
        Current.Shutdown();

    }
    else
    {
        //Инициализируем окно
        MainWindow window = new MainWindow();
        window.Show();
    }
}

Далее приведу пример кода с вопросом, как в примере для Windows Forms.

App.xaml:

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
    </Application.Resources>
</Application>

App.xaml.cs:

using System.Windows;
using System.Security.Principal;
using System.Diagnostics;
using System.Reflection;

namespace WpfApp1
{
    /// <summary>
    /// Логика взаимодействия для App.xaml
    /// </summary>
    public partial class App : Application
    {
        //Переопределяем метод OnStartup
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            //Если программа запускается НЕ от имени администратора
            if (!IsRunningAsAdmin())
            {

                //Спросим нужно ли использовать права админа
                MessageBoxResult result = MessageBox.Show("Запустить программу от имени администратора?", 
                    "Запуск от имени администратора",
                    MessageBoxButton.YesNo, 
                    MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                {
                    // Настройка информации о новом процессе нашего приложения
                    ProcessStartInfo processStartInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase);
                    // Настройка ProcessStartInfo. Ключевое слово «runas» позволит запустить процесс от имени администратора
                    processStartInfo.UseShellExecute = true;
                    processStartInfo.Verb = "runas";

                    // Запуск нового процесса нашего приложения
                    try
                    {
                        Process.Start(processStartInfo);
                    }
                    catch
                    {
                        Current.Shutdown();
                    };

                    // Остановка старого процесса
                    Current.Shutdown();
                }
                else
                {
                    MainWindow window = new MainWindow();
                    window.Show();
                }
            }
            else
            {
                //Инициализируем окно
                MainWindow window = new MainWindow();
                window.Show();
            }
        }

        /// <summary>
        /// Проверка прав администратора
        /// </summary>
        /// <returns></returns>
        bool IsRunningAsAdmin()
        {
            //Получим пользователя
            WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
            //Получим роль
            WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
            //Вернём ТРУ, если приложение имеет права администратора
            return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
        }
    }
}

Пример работы WPF-программы:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.