Как повысить привилегии только в случае необходимости?

Этот вопрос относится к Windows Vista!

У меня есть приложение, которое обычно работает без административных привилегий. Существует один вид действия, который требует административных привилегий, но я не хочу запускать приложение с более высокими привилегиями, когда я знаю, что большая часть времени пользователь даже не использует эту функцию.

Я думаю об определенном методе, с помощью которого я могу повысить привилегии приложения на каком-либо событии (например, нажатие кнопки). Пример:

Если пользователь нажмет эту кнопку, ему будет предложено диалоговое окно UAC или согласие. Как я могу это сделать?

Ответ 1

Я не считаю, что можно поднять текущий процесс. Как я понимаю, он встроен в Windows Vista, когда права администратора предоставляются процессу при запуске. Если вы посмотрите на различные программы, которые используют UAC, вы должны увидеть, что они фактически запускают отдельный процесс каждый раз, когда необходимо выполнить административное действие (диспетчер задач - один, Paint.NET - это другой, последний из которых является .NET-приложением на самом деле).

Типичным решением этой проблемы является указание аргументов командной строки при запуске повышенного процесса (одно из возможных действий - это предложение abatishchev), так что запущенный процесс знает только, чтобы отобразить определенное диалоговое окно, а затем выйти после этого действие завершено. Таким образом, для пользователя не должно быть заметно, чтобы новый процесс был запущен, а затем вышел из него и скорее появлялся, как если бы было открыто новое диалоговое окно в одном и том же приложении (особенно, если вы обнаружили хакерство, чтобы сделать главное окно повышенный процесс - дочерний процесс родительского процесса). Если вам не нужен интерфейс для повышенного доступа, еще лучше.

Для полного обсуждения UAC на Vista я рекомендую вам увидеть это в статье по этому вопросу (примеры кода на С++, но Я подозреваю, что вам придется использовать WinAPI и P/Invoke для выполнения большинства вещей на С# в любом случае). Надеюсь, вы, по крайней мере, видите правильный подход, хотя разработка UAC-совместимой программы далека от тривиальной...

Ответ 2

Как было сказано там:

Process.StartInfo.UseShellExecute = true;
Process.StartInfo.Verb = "runas";

запустит процесс как администратор, чтобы сделать все, что вам нужно, с реестром, но вернитесь к своему приложению с нормальными привилегиями.

Ответ 3

В следующей статье 981778 MSDN KB описано, как "самоподнять" приложение:

http://support.microsoft.com/kb/981778

Он содержит загружаемые образцы в Visual С++, Visual С#, Visual Basic.NET.

Этот подход связан с необходимостью запуска отдельного процесса, но на самом деле это первоначальное приложение, которое перезапускается, работает как повышенный пользователь. Тем не менее, это может быть очень полезно в некоторых контекстах, где нецелесообразно дублировать код в отдельном исполняемом файле.

Чтобы удалить высоту, вам нужно выйти из приложения.

Ответ 5

Я знаю, что это старый пост, но это отвечает всем, кто встречает предложение MarcP. Сообщение msdn, на которое он ссылается, действительно перезапускает приложения во всех примерах кода. Образцы кода используют глагол runas, предложенный уже в других предложениях.

Я загрузил код, чтобы убедиться, но это из оригинальной статьи msdn:

4. Нажмите "Да", чтобы подтвердить высоту. Затем исходное приложение     перезапускается, работает как повышенный администратор.
 5. Закройте приложение.

Ответ 6

Возможно, кому-то пригодится этот простой пример:

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

namespace WindowsFormsApp1
{
    internal static class Program
    {
        private class Form1 : Form
        {
            internal Form1()
            {
                var button = new Button{ Dock = DockStyle.Fill };
                button.Click += (sender, args) => RunAsAdmin();
                Controls.Add(button);

                ElevatedAction();
            }
        }

        [STAThread]
        internal static void Main(string[] arguments)
        {
            if (arguments?.Contains("/run_elevated_action") == true)
            {
                ElevatedAction();
                return;
            }

            Application.Run(new Form1());
        }

        private static void RunAsAdmin()
        {
            var path = Assembly.GetExecutingAssembly().Location;
            using (var process = Process.Start(new ProcessStartInfo(path, "/run_elevated_action")
            {
                Verb = "runas"
            }))
            {
                process?.WaitForExit();
            }
        }

        private static void ElevatedAction()
        {
            MessageBox.Show([email protected]"IsElevated: {IsElevated()}");
        }

        private static bool IsElevated()
        {
            using (var identity = WindowsIdentity.GetCurrent())
            {
                var principal = new WindowsPrincipal(identity);

                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
        }

    }
}