Сегодня мы рассмотрим способ, который позволит приложению 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-программы: