Правильный способ борьбы с UAC в C # - PullRequest
14 голосов
/ 13 октября 2010

У меня есть приложение (служба Windows), которое установлено в каталог в папке Program Files. Наряду с этим приложением есть еще одно приложение WinForms, которое используется для настройки службы (помимо прочего). Когда он выполняет настройку, он сохраняет изменения в файле конфигурации, который находится рядом со службой.

При работе в Vista / Win7 UAC не позволяет пользователю сохранить файл конфигурации. То, что я хотел бы сделать, это:

  • поместите значок щита рядом с пунктом меню, используемым для настройки
  • запрашивать разрешения UAC при выборе этого пункта
  • отображать значок / подсказку только в ОС, для которой она требуется
  • показывает значок / приглашение только тогда, когда требуются разрешения (например, если приложение установлено где-то, для которого не требуется разрешение UAC)

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

Как мне лучше всего этого добиться?

Ответы [ 2 ]

21 голосов
/ 13 октября 2010

Это довольно просто.Поместите значок щита на кнопку, которая сохраняет изменения в файле конфигурации, вместо пункта меню.Это следует за поведением Windows: не запрашивать разрешения UAC до последнего момента.Кнопка фактически запустит ваш исполняемый файл снова как администратор со специальной командной строкой (которую вы решите), чтобы выполнить сохранение файла конфигурации.Используйте именованный канал (обязательно предоставьте ему правильные разрешения) для передачи данных конфигурации во второй экземпляр, если вы не хотите использовать командную строку для передачи данных.

Для запуска вашего исполняемого файла:

ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "YOUR EXE";
info.UseShellExecute = true;
info.Verb = "runas"; // Provides Run as Administrator
info.Arguments = "YOUR SPECIAL COMMAND LINE";

if (Process.Start(info) != null)
{ 
    // The user accepted the UAC prompt.
}

Это также работает, когда UAC не существует (Windows XP), потому что он будет просто запускаться от имени администратора, если это возможно, или запрашивать учетные данные.Вы можете проверить, требует ли ОС UAC, просто набрав Environment.OSVersion.Version.Major == 6.6 - это и Windows Vista, и 7. Вы можете убедиться, что используете Windows, взглянув на Environment.OSVersion.Platform.

. Чтобы определить, является ли ваше приложение администратором, вы можете сделать следующее:1011 *

9 голосов
/ 26 апреля 2013

Ответ Мэтью Феррейры подробно описывает, почему вам нужно перезапустить все приложение и что делать, когда его перезапустить, однако он не рассказал, как отобразить значок щита. Вот некоторый код, который я использую (я думаю, что я первоначально получил его от другого ответа где-то на этом сайте), который будет показывать значок щита только тогда, когда программа не повышена

/// <summary>
/// Is a button with the UAC shield
/// </summary>
public partial class ElevatedButton : Button
{
    /// <summary>
    /// The constructor to create the button with a UAC shield if necessary.
    /// </summary>
    public ElevatedButton()
    {
        FlatStyle = FlatStyle.System;
        if (!IsElevated()) ShowShield();
    }


    [DllImport("user32.dll")]
    private static extern IntPtr
        SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    private uint BCM_SETSHIELD = 0x0000160C;

    private bool IsElevated()
    {
        WindowsIdentity identity = WindowsIdentity.GetCurrent();
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        return principal.IsInRole(WindowsBuiltInRole.Administrator);
    }


    private void ShowShield()
    {
        IntPtr wParam = new IntPtr(0);
        IntPtr lParam = new IntPtr(1);
        SendMessage(new HandleRef(this, Handle), BCM_SETSHIELD, wParam, lParam);
    }
}

Кнопка проверяет, когда она создается, находится ли она в административном контексте, а если нет, то рисует значок щита на кнопке.

Если вы хотите, чтобы в Windows использовали значок щита, - это хитрый трюк , который возвращает значок щита как Bitmap объект.

...