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!
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With