如何运行需要提升并等待的子进程?

时间:2011-02-04 00:11:49

标签: c++ winapi uac shellexecute createprocess

胜利7 / UAC让我发疯。

在我的C ++应用程序中,我需要在Windows 7上运行需要提升的可执行文件。我想解决这个问题并等待它继续完成。最简单的方法是什么?

我通常会通过CreateProcess()执行此类操作,但对于需要提升的可执行文件,它会失败。

我尝试使用cmd.exe /c ...通过CreateProcess运行,但它可以正常运行,但会弹出一个丑陋的cmd终端窗口。

我正在读ShellExecute()允许提升,但在使用ShellExecute()时等待exe完成似乎并不容易。 像system()这样简单的东西会起作用吗?

非常感谢任何其他想法!

3 个答案:

答案 0 :(得分:42)

使用 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指定“runas”动词是导致UAC提升即将启动的应用程序的原因。这相当于将应用程序清单中的权限级别设置为“requireAdministrator”。管理员和受限用户都需要UAC提升。

但值得注意的是,除非绝对必要,否则您应该更喜欢向要启动的应用程序添加清单的“标准”方式,以指定其所需的执行级别。如果你走这条路线,你只需将“开放”作为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提升的进程marked accordingly。在用户界面中对此进行建模是您的工作; Windows无法为您处理它。这是通过在入口点上显示盾牌图标来完成的;例如:

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

答案 1 :(得分:0)

您可以做的是为子进程“stdin”创建一个管道(就像您将输入重定向到该进程一样)并等待管道中断。

请注意,该过程不会真正收到重定向的输入。

E.g。如果你尝试从无法使用的命令提示符

echo help | diskpart

您将看到高程,命令窗口将等待您关闭单独的窗口。

答案 2 :(得分:0)

要使用提升的特权运行,需要启动此进程的进程具有提升的特权。这通常需要安全的服务或已经运行的东西才能启动您的流程。这是从Vista开始的变化。它与拥有权限(通过您的ACL令牌)能够启动进程并使用从启动进程继承的适当级别的特权启动它有关。微软一直在努力让人们创建一个处理所有提升功能需求的高级流程,并将其余部分留在最不具有权限的用户空间中。自从Vista成为Alpha之后,一直在这样做。这是一种痛苦,但出于安全原因,微软希望你做的事情。

顺便说一下,如果你从Program Files目录等安全位置启动你的应用程序,那么ShellExec调用将不起作用。在多年前不得不转移到服务模型之前尝试过。

因此,要启动您的流程并通过UAC,唯一的方法是从已具有继承权限的流程启动