33

Win 7/UAC 快把我逼疯了。

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

我通常通过 来做这种事情CreateProcess(),但是对于需要提升的可执行文件来说它失败了。

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

我正在阅读这ShellExecute()将允许提升,但在使用ShellExecute(). 像这样简单的事情会system()起作用吗?

非常感谢任何其他想法!

4

3 回答 3

47

使用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 盾牌                                     菜单项上显示的 UAC 盾牌

于 2011-02-04T00:59:35.623 回答
0

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

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

例如,如果您尝试从未提升的命令提示符执行

echo help | diskpart

您将看到海拔高度,命令窗口将等到您关闭单独的窗口。

于 2011-02-04T00:28:46.423 回答
0

要以提升的特权运行,要求启动它的进程具有提升的特权。这通常需要一个安全的服务或已经运行的东西来启动你的进程。这是从 Vista 开始的更改。它与授权(通过您的 ACL 令牌)能够启动进程并使用从启动进程继承的适当级别的特权启动它有关。微软一直在努力让人们创建一个提升的进程来处理所有提升的功能需求,并将其余的留在特权最低的用户空间。自从 Vista 是 Alpha 版以来,就一直在这样做。这很痛苦,但出于安全原因,Microsoft 希望您这样做。

顺便说一句,如果您从程序文件目录等安全位置启动您的应用程序,ShellExec 调用将不起作用。在几年前不得不转移到服务模型之前尝试过。

因此,要启动您的进程并通过 UAC,唯一的方法是从已经具有继承安全特权的进程启动

于 2011-08-07T18:52:27.450 回答