2010-08-29 3 views
13

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

делать дальше:

var info = new ProcessStartInfo(Assembly.GetEntryAssembly().Location) 
{ 
    UseShellExecute = true, // ! 
    Verb = "runas", 
}; 

var process = new Process 
{ 
    StartInfo = info 
}; 

process.Start(); 

и это работает:

var identity = new WindowsPrincipal(WindowsIdentity.GetCurrent()); 
identity.IsInRole(WindowsBuiltInRole.Administrator); // returns true 

Но UseShellExecute = true создает новое окно, и я также не могу перенаправить вывод.

Так что, когда я делаю следующий:

var info = new ProcessStartInfo(Assembly.GetEntryAssembly().Location) 
{ 
    RedirectStandardError = true, 
    RedirectStandardOutput = true, 
    UseShellExecute = false, // ! 
    Verb = "runas" 
}; 

var process = new Process 
{ 
    EnableRaisingEvents = true, 
    StartInfo = info 
}; 

DataReceivedEventHandler actionWrite = (sender, e) => 
{ 
    Console.WriteLine(e.Data); 
}; 

process.ErrorDataReceived += actionWrite; 
process.OutputDataReceived += actionWrite; 

process.Start(); 
process.BeginOutputReadLine(); 
process.BeginErrorReadLine(); 
process.WaitForExit(); 

Это не повышение привилегий и выше код возвращает ложь. Зачем??

+0

Кстати, вы можете написать 'DataReceivedEventHandler actionWrite = ...' и 'process.ErrorDataReceived + = actionWrite'. – SLaks

+0

Можете ли вы протестировать с помощью UseShellExecute = true, Verb = "runas", а события ErrorDataReceived - как комментарий @SLaks? – Kiquenet

ответ

14

ProcessStartInfo.Verb будет иметь эффект, только если процесс запущен ShellExecuteEx(). Для чего требуется UseShellExecute = true. Перенаправление ввода-вывода и скрытие окна могут работать, только если процесс запускается CreateProcess(). Для этого требуется UseShellExecute = false.

Ну, вот почему это не работает. Не уверен, что запрет запуска скрытого процесса, который обходит UAC, был намеренным. Вероятно. Очень возможно.

Проверьте, есть ли в манифесте this Q+A запрос на повышение UAC.

+0

Большое спасибо за описание WinAPI за сценой. Как вы думаете, возможно ли получить повышенные привилегии по требованию для процесса со скрытым окном? Или это взаимоисключающие вещи? – abatishchev

+0

И можно ли включить/выключить использование манифеста? То есть когда я запускаю свое приложение впервые (вручную) - не используйте манифест, когда второй (программный) - принудительно используется. – abatishchev

+0

Запуск процесса с повышенными привилегиями без возможности узнать об этом пользователя. Вам нужен отдельный .exe, чтобы он имел свой собственный манифест. В основном вам нужен только метод Main(). –

0

Проверить this answer.

Это, как представляется, обеспечивает обходное решение. Но я рекомендую попробовать другие методы, такие как Named Pipes, когда у вас есть доступ к исходному коду дочернего процесса.

+1

Я не тестировал подход статьи UAC, хотя он содержит образец сам по себе. Но если вы имеете в виду образец для Named Pipes, вы можете легко найти многие из них (например [this] (http://stackoverflow.com/questions/13806153/example-of-named-pipes) или [это] (http: //www.codeproject.com/Tips/492231/Csharp-Async-Named-Pipes)) с небольшим поиском. Дело в том, что, как перенаправление ввода-вывода, вы также можете использовать текстовые потоки с помощью Named Pipes, чтобы отправлять и получать данные (даже если эти два процесса находятся на разных машинах). Конечно, вам нужно иметь дело с некоторыми нюансами, чтобы получить полностью работоспособное приложение. –

+0

@abatishchev IMHO, лучше использовать Trace to File, а не перенаправить вывод, глагол = runas. Именованные каналы намного сложнее и сложнее для легкой отладки. – Kiquenet

2

В моем случае было нормально получать выходные данные после того, как завершен дочерний процесс. Вот решение, которое я придумал. Он использует временный файл:

var output = Path.GetTempFileName(); 
var process = Process.Start(new ProcessStartInfo 
{ 
    FileName = "cmd", 
    Arguments = "/c echo I'm an admin > " + output, // redirect to temp file 
    Verb = "runas", // UAC prompt 
    UseShellExecute = true, 
}); 
process.WaitForExit(); 
string res = File.ReadAllText(output); 
// do something with the output 
File.Delete(output); 
+0

это действительно работает для меня. свернутые детали (окна 10, F #) на https://gist.github.com/ImaginaryDevelopment/f4bc33ae75bdf29e5aad8fd4045f193d – Maslow

+0

Принятый ответ - это объяснение, это решение .. +1 – caesay