Правильный способ борьбы с ОАК в C#
У меня есть приложение (служба Windows), которое установлено в каталог в папке Program Files. Наряду с этим приложением является еще одно приложение WinForms, которое используется для настройки службы (среди прочего). Когда он выполняет настройку, он сохраняет изменения в конфигурационном файле, который живет рядом со службой.
при работе в Vista / Win7 UAC запрещает пользователю сохранять файл конфигурации. То, что я хотел бы сделать, это:
- поставить значок экрана рядом с пунктом меню, используемым для настройки
- запрос разрешений UAC, когда этот элемент выбран
- показывать значок / приглашение только в ОС, которая требует его
- показывать только значок / приглашение, когда требуются разрешения (например. если приложение установлено где-то, что не требует разрешения UAC)
Я действительно не хочу запускать все приложение в качестве администратора, так как оно также используется для других целей, которые не требуется разрешение UAC (поэтому установка файла манифеста приложения не является правильным решением). Я также предполагаю (исправьте меня, если я ошибаюсь), что как только разрешения UAC были предоставлены, мой существующий процесс не может выполнить действие и что мне нужно будет начать новый процесс.
Как я могу лучше всего достичь этого?
2 ответов
Это довольно легко. Поместите значок экрана на кнопку, которая сохраняет изменения в файле конфигурации, вместо пункта меню. Это следует за поведением 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
.
для обнаруживать ли вы приложение уже admin, вы можете сделать это:
public static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity != null)
{
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
return false;
}
ответ Мэтью Феррейры переходит к деталям о том, почему вам нужно перезапустить все приложение и что делать, когда перезапустить его, однако он не охватывает, как показать значок щита. Вот некоторый код, который я использую (я думаю, что изначально получил его из другого ответа где-то на этом сайте), который будет показывать значок экрана только тогда, когда программа не повышена
/// <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 использует,вот подлый трюк это возвращает значок щита как