我如何运行需要提升和等待的subprocess?
Win 7 / UAC让我疯狂。
在我的C ++应用程序中,我需要运行一个需要在Windows 7上升级的可执行文件。我想要解决这个问题并等待它完成后再继续。 什么是最简单的方法来做到这一点?
我通常通过CreateProcess()
来做这种事情,但是对于那些需要提升的可执行文件来说,这是失败的。
我尝试运行使用cmd.exe /c ...
通过CreateProcess
,它的工作,但popup一个丑陋的cmdterminal窗口。
我正在阅读的ShellExecute()
将允许提升,但它似乎并不容易等待exe完成使用ShellExecute()
。 会像system()
一样简单的工作吗?
任何其他的想法,非常感谢!
使用ShellExecuteEx
而不是ShellExecute
。 该函数将为创build的进程提供一个句柄,您可以使用该句柄来调用该句柄上的WaitForSingleObject
,直到该进程终止。 最后,在进程CloseHandle
上调用CloseHandle
来closures它。
示例代码(为了清晰和简洁,省略了大部分错误检查):
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”。 这将需要pipe理员和受限用户的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提升的进程的执行。 在用户界面中对此进行build模是您的工作。 Windows不会为你处理它。 这是通过在入口点上显示盾牌图标来完成的; 例如:
你可以做的是为subprocess“stdin”创build一个pipe道(就好像你将inputredirect到该进程)并等待pipe道中断。
请注意,该进程将不会真正收到redirect的input。
例如,如果你尝试从未升级的命令提示符来做
echo help | diskpart
你会看到海拔和命令窗口将等待,直到你closures了单独的窗口。
要使用提升的特权运行,需要启动该进程的权限已提升。 这通常需要一个安全的服务或已经运行的东西来启动你的过程。 这是从Vista开始的一个改变。 它必须通过授予权限(通过ACL令牌)来启动进程并使用从启动进程inheritance的相应级别的特权启动进程。 微软一直在努力让人们创build一个提升的进程来处理所有提升的function需求,剩下的用户空间最less。 自从Vista成为Alpha以来,一直这样做。 这是一个痛苦,但微软宁愿你为了安全的原因而做事。
顺便说一下,如果您从Program Files目录等安全位置启动您的应用程序,则ShellExec调用将不起作用。尝试在几年前不得不转移到服务模型之前。
所以要启动你的进程并通过UAC,唯一的办法就是从一个已经拥有安全特权的进程启动inheritance