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

Ken*_*enG 30 c++ winapi uac createprocess shellexecute

Win 7/UAC让我发疯.

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

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

我尝试使用cmd.exe /c ...直通CreateProcess,它可以工作,但弹出一个丑陋的cmd终端窗口.

我正在阅读,这ShellExecute()将允许提升,但使用时等待exe完成似乎并不容易ShellExecute().像system()工作一样简单吗?

非常感谢任何其他想法!

Cod*_*ray 45

使用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);
}
Run Code Online (Sandbox Code Playgroud)

为此指定"runas"动词lpVerb是导致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>
Run Code Online (Sandbox Code Playgroud)

最后,确保应用程序中的任何元素触发执行需要UAC提升的进程,并相应标记.在用户界面中对此进行建模是您的工作; Windows无法为您处理它.这是通过在入口点上显示盾牌图标来完成的; 例如:

        UAC屏蔽显示在按钮上                                     UAC屏蔽显示在菜单项上

  • @MichalHosala:因此,如果清单显示"requireAdministrator"并且产卵过程没有提升,则`CreateProcess()`将失败,并显示`ERROR_ELEVATION_REQUIRED`. (3认同)
  • @MichalHosala:不,你是对的.Per [Vista UAC:The Definitive Guide](http://www.codeproject.com/Articles/19165/Vista-UAC-The-Definitive-Guide):"CreateProcess()失败,因为Vista中需要通过它们进行提升的进程清单文件.应该注意清单文件并没有真正说"你必须使用管理令牌来启动这个过程".相反,它说,"你不能使用少于这些权限的令牌来启动这个过程".因此,从CreateProcess(),ERROR_ELEVATION_REQUIRED(740)返回的错误消息有点误导." (2认同)
  • 应该明确指出,根据其他评论,如果清单中有适当的要求,你*不需要*在 SHELLEXECUTEINFO 结构的 `lpVerb` 成员中使用 `runas`,但你*需要*如果调用进程尚未提升,则使用“ShellExecuteEx”而不是“CreateProcess”。您可以从其他评论中推断出这一点,但尚未明确说明。 (2认同)