Как запустить дочерний процесс, требующий повышения и ожидания?

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

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

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

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

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

любые другие идеи с благодарностью!

3 ответов


использовать 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);
}

С указанием глагол "руны" для 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


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

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

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

echo help | diskpart

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


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

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

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