Как я могу запустить дочерний процесс, который требует повышения прав и ожидания? - PullRequest
30 голосов
/ 04 февраля 2011

Win 7 / UAC сводит меня с ума.

Из моего приложения C ++ мне нужно запустить исполняемый файл, требующий повышения прав в Windows 7. Я хочу запустить эту вещь и дождаться ее завершенияпрежде чем продолжить.Какой самый простой способ сделать это?

Обычно я делаю такие вещи через CreateProcess(), но это не удается для исполняемых файлов, требующих повышения прав.

Я пытался запустить с помощью cmd.exe /c ... через CreateProcess, который работает, но выдает уродливое окно терминала cmd.

Я читаю, что ShellExecute() позволит повысить, но не так-то просто дождаться завершения exe при использовании ShellExecute().Будет ли работать что-то простое, например system()?

Любые другие идеи очень ценятся!

Ответы [ 3 ]

42 голосов
/ 04 февраля 2011

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

Пример кода (большая часть проверки ошибок опущена для ясности и краткости):

SHELLEXECUTEINFO shExInfo = {0};
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExInfo.hwnd = 0;
shExInfo.lpVerb = _T("runas");                // Operation to perform
shExInfo.lpFile = _T("C:\\MyApp.exe");       // Application to start    
shExInfo.lpParameters = "";                  // Additional parameters
shExInfo.lpDirectory = 0;
shExInfo.nShow = SW_SHOW;
shExInfo.hInstApp = 0;  

if (ShellExecuteEx(&shExInfo))
{
    WaitForSingleObject(shExInfo.hProcess, INFINITE);
    CloseHandle(shExInfo.hProcess);
}

Указание глагола "runas" для lpVerb - это то, что заставляет UAC поднять приложение, которое должно быть запущено. Это эквивалентно установке уровня разрешений в манифесте приложения на «requireAdministrator». Это потребует повышения прав UAC как для администратора, так и для пользователя с ограниченными правами.

Но стоит отметить, что, если в этом нет абсолютной необходимости, вы должны предпочесть «стандартный» способ добавления манифеста к приложению, которое вы хотите запустить, который задает требуемый уровень выполнения. Если вы пойдете по этому маршруту, вы просто передадите «open» как lpVerb. Пример манифеста показан ниже:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <dependency>
                <dependentAssembly>
                        <assemblyIdentity
                                type="win32"
                                name="Microsoft.Windows.Common-Controls"
                                version="6.0.0.0"
                                processorArchitecture="X86"
                                publicKeyToken="6595b64144ccf1df"
                                language="*"
                        />
                </dependentAssembly>
        </dependency>
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
                <security>
                        <requestedPrivileges>
                                <requestedExecutionLevel 
                                       level="requireAdministrator" 
                                       uiAccess="false"/>
                        </requestedPrivileges>
                </security>
        </trustInfo>
</assembly>

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

UAC shield displayed on a button UAC shield displayed on a menu item

0 голосов
/ 07 августа 2011

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

Между прочим, вызов ShellExec не будет работать, если вы запускаете свое приложение из безопасного места, такого как каталог Program Files и т. Д. Попробовал это перед переходом на модель сервиса несколько лет назад.

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

0 голосов
/ 04 февраля 2011

Что вы можете сделать, это создать канал для дочернего процесса "stdin" (как если бы вы перенаправили ввод в этот процесс) и подождать, пока канал прервется.

Обратите внимание, что процесс на самом деле не получит перенаправленный ввод.

например. если вы попытаетесь из командной строки без изменений сделать

echo help | diskpart

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

...