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

发布于 2024-10-16 02:41:13 字数 428 浏览 2 评论 0 原文

Win 7/UAC 让我发疯。

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

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

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

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

任何其他想法将不胜感激!

Win 7/UAC is driving me crazy.

From within my C++ application, I need to run an executable that requires elevation on Windows 7. I want to fire this thing off and wait for it to finish before proceeding. What's the easiest way to do this?

I normally do this kind of thing via CreateProcess(), but it fails for executables that require elevation.

I tried running using cmd.exe /c ... through CreateProcess, which works but pops up an ugly cmd terminal window.

I am reading that ShellExecute() will allow elevation, but it doesn't appear to be easy to wait for the exe to finish when using ShellExecute().
Will something simple like system() work?

Any other ideas are greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北城孤痞 2024-10-23 02:41:13

使用 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。

但值得注意的是,除非绝对必要,否则您应该更喜欢使用“标准”方式将清单添加到要启动的应用程序中,以指定其所需的执行级别。如果您选择这条路线,您只需将“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 屏蔽显示在按钮上   ;                         NBSP ;        
UAC 屏蔽显示在菜单项上

Use ShellExecuteEx, rather than ShellExecute. This function will provide a handle for the created process, which you can use to call WaitForSingleObject on that handle to block until that process terminates. Finally, just call CloseHandle on the process handle to close it.

Sample code (most of the error checking is omitted for clarity and brevity):

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

Specifying the "runas" verb for the lpVerb is what causes UAC to elevate the application that's about to be launched. This is the equivalent of setting the permissions level in the application's manifest to "requireAdministrator". It will require UAC elevation for both an administrator and a limited user.

But it's worth noting that unless absolutely necessary, you should prefer the "standard" way of adding a manifest to the application you want to launch that specifies its required execution level. If you go this route, you will simply pass "open" as the lpVerb. A sample manifest is shown below:

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

Finally, make sure that whatever element in your application triggers execution of the process requiring UAC elevation is marked accordingly. It's your job to model this in the user interface; Windows doesn't handle it for you. This is done by displaying the shield icon on the entry point; for example:

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

独留℉清风醉 2024-10-23 02:41:13

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

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

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

echo help | diskpart

您将看到提升,并且命令窗口将等待,直到您关闭单独的窗口。

What you can do is create a pipe for the child process "stdin" (as if you were to redirect the input to that process) and wait for the pipe to break.

Note that the process will not really receive the redirected input.

E.g. if you try from unelevated command prompt to do

echo help | diskpart

you will see elevation and the command window will wait until you close the separate window.

她说她爱他 2024-10-23 02:41:13

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

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

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

To run with elevated privileged, requires that the process launching this has elevated privileged. This usually require a secure service or something already running to launch your process. This is a change starting with Vista. It has to do with having the authority (via your ACL tokens) to be able to launch a process and launch it with the appropriate level of privileged inherited from the launching process. Microsoft has been pushing hard to have people create an elevated process that handles all elevated functionality needs and leave the rest in least privileged user space. Been doing this off and on since Vista was Alpha. It's a pain, but the way Microsoft would prefer you to do things for security reasons.

By the way, the ShellExec call will not work if you are launching your app from a secure location like Program Files directory, etc. Tried that before having to move to the service model years ago.

So to launch your process and by pass UAC, the only way to do it is to launch from a process that already has the security privileged to inherit

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文