¿Cómo puedo ejecutar un proceso hijo que requiere elevación y espera?


Win 7/UAC me está volviendo loco.

Desde mi aplicación de C++, necesito ejecutar un ejecutable que requiera elevación en Windows 7. Quiero disparar esta cosa y esperar a que termine antes de proceder. ¿Cuál es la forma más fácil de hacer esto?

Normalmente hago este tipo de cosas a través de CreateProcess(), pero falla para ejecutables que requieren elevación.

He intentado ejecutar usando cmd.exe /c ... a través de CreateProcess, que funciona pero aparece una ventana de terminal cmd fea.

Yo soy leer que ShellExecute() permitirá la elevación, pero no parece ser fácil esperar a que el exe termine cuando se usa ShellExecute(). ¿Funcionará algo simple como system()?

Cualquier otra idea es muy apreciada!

Author: Cody Gray, 2011-02-04

3 answers

Uso ShellExecuteEx, en lugar de ShellExecute. Esta función proporcionará un controlador para el proceso creado, que puede usar para llamar WaitForSingleObject en esa manija para bloquear hasta que el proceso termine. Finalmente, solo llama CloseHandle en la manija del proceso para cerrarlo.

Código de ejemplo (la mayor parte de la comprobación de errores se omite por claridad y brevedad):

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);
}

Especificar el verbo "runas" para el lpVerb es lo que hace que UAC eleve el aplicación que está a punto de ser lanzada. Esto es el equivalente de establecer el nivel de permisos en el manifiesto de la aplicación a "requireAdministrator". Requerirá elevación de UAC tanto para un administrador como para un usuario limitado.

Pero vale la pena señalar que a menos que sea absolutamente necesario, debería preferir la forma "estándar" de agregar un manifiesto a la aplicación que desea lanzar que especifique su nivel de ejecución requerido. Si va por esta ruta, simplemente pasará "abierto" como el lpVerb. A continuación se muestra un manifiesto de muestra:

<?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>

Finalmente, asegúrese de que cualquier elemento en su aplicación desencadene la ejecución del proceso que requiere elevación de UAC esté marcado en consecuencia. Es su trabajo modelar esto en la interfaz de usuario; Windows no lo maneja por usted. Esto se hace mostrando el icono de escudo en el punto de entrada; por ejemplo:

        Escudo UAC mostrado en un botón                                     Escudo UAC mostrado en un elemento de menú

 39
Author: Cody Gray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-08 05:14:38

Lo que puede hacer es crear una tubería para el proceso hijo "stdin" (como si fuera a redirigir la entrada a ese proceso) y esperar a que la tubería se rompa.

Tenga en cuenta que el proceso realmente no recibirá la entrada redirigida.

Por ejemplo, si intenta desde el símbolo del sistema no mejorado para hacer

echo help | diskpart

Verá elevación y la ventana de comandos esperará hasta que cierre la ventana separada.

 0
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-04 00:28:46

Para ejecutarse con privilegios elevados, se requiere que el proceso que inicia esto tenga privilegios elevados. Esto generalmente requiere un servicio seguro o algo que ya se esté ejecutando para iniciar su proceso. Este es un cambio que comienza con Vista. Tiene que ver con tener la autoridad (a través de sus tokens ACL) para poder lanzar un proceso y lanzarlo con el nivel apropiado de privilegios heredados del proceso de lanzamiento. Microsoft ha estado presionando duro para que la gente cree un proceso elevado eso maneja todas las necesidades de funcionalidad elevadas y deja el resto en el espacio de usuario menos privilegiado. He estado haciendo esto de vez en cuando desde que Vista era Alfa. Es un dolor, pero la forma en que Microsoft prefiere hacer las cosas por razones de seguridad.

Por cierto, la llamada de ShellExec no funcionará si está lanzando su aplicación desde una ubicación segura como el directorio de archivos de programa, etc. Lo intenté antes de tener que pasar al modelo de servicio hace años.

Así que para iniciar su proceso y by pass UAC, la única manera de hacerlo es lanzar desde un proceso que ya tiene la seguridad privilegiada para heredar

 0
Author: Greg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-07 18:52:27