How can I run a child process that requires elevation and wait?
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:
How to run a process with ShellExecuteEx as as a child that closes after parent exit?
You have the use the shell verb runas
to force elevation. Which rules out CreateProcess
. So you can do the following:
- Use
ShellExecuteEx
to create the child process. - Arrange for
ShellExecuteEx
to return a process handle for the child. - When the parent terminates, terminate the child.
If you want to use jobs to tie the processes lives together then you need to include the requiresAdministrator
manifest option of the child. That way you can use CreateProcess
and specify the process creation flags as you desire.
Now, you may wish not to have the child process manifested that way. If so then you can still get the job done with a call to CreateProcess
. You need three processes:
- Parent process, runs as standard user.
- Launcher process, manifested to be elevated. Created by parent, with appropriate job flags, and passed arguments that specify how to launch child. Which it does with
CreateProcess
and placed in same job. - Child process. Not manifested to be elevated. But because it is launched by the elevated launcher it too is elevated.
The point here is that there are two ways to force elevation. Statically at compile time with a manifest. That allows you to use CreateProcess
. Or dynamically with the runas
shell verb. That forces ShellExecuteEx
. You state that you are pushed to CreateProcess
, and so that means the use of a manifest to force elevation.
How to run application which requires admin rights from one that doesn't have them
Real problem: (from Wikipedia: http://en.wikipedia.org/wiki/User_Account_Control)
An executable that is marked as "requireAdministrator" in its manifest cannot be started from a non-elevated process using CreateProcess(). Instead, ERROR_ELEVATION_REQUIRED will be returned. ShellExecute() or ShellExecuteEx() must be used instead.
(BTW, ERROR_ELEVATION_REQUIRED error == 740)
Solution: (same site)
In a native Win32 application the same "runas" verb can be added to a ShellExecute() or ShellExecuteEx() call.
ShellExecute(hwnd, "runas", "C:\\Windows\\Notepad.exe", 0, 0, SW_SHOWNORMAL);
This may be also helpful: (source: http://mark.koli.ch/2009/12/uac-prompt-from-java-createprocess-error740-the-requested-operation-requires-elevation.html)
2 - Basic UAC Flow
Ok, so before you dig into it, I thought it might be helpful to explain the basic flow of a UAC aware application and how everything fits together. Normally, your application runs as an unprivileged user. But, sometimes it needs to be an Administrator (to do whatever). So, here's the basic idea, in pseudo code:
int main (int argc, char **argv) {
HRESULT operation = tryToDoSomethingPrivileged();
if (operation == ACCESS_DENIED && !alreadyElevated) {
// Spawn a copy of ourselves, via ShellExecuteEx().
// The "runas" verb is important because that's what
// internally triggers Windows to open up a UAC prompt.
HANDLE child = ShellExecuteEx(argc, argv, "runas");
if (child) {
// User accepted UAC prompt (gave permission).
// The unprivileged parent should wait for
// the privileged child to finish.
WaitForSingleObject(child, INFINITE);
CloseHandle(pid);
}
else {
// User rejected UAC prompt.
return FAILURE;
}
return SUCCESS;
}
return SUCCESS;
}
Finally, this is how I've done it:
if(0 == CreateProcess(argv[2], params, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) {
//runas word is a hack to require UAC elevation
ShellExecute(NULL, "runas", argv[2], params, NULL, SW_SHOWNORMAL);
}
And just for completness's sake - MSDN links to ShellExecute and CreateProcess:
http://msdn.microsoft.com/en-us/library/bb762153%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx
how could I call privileged(need administrator privilege) programs from normal privileged programs?
If you are using Visual Studio, the easiest method is this; under project properties, under Linker section set "UAC Execution Level" to requireAdministrator.
You can manually create a manifest file if you are using another build environment.
How to wait for a cloned child process of an invoked process to exit?
+1 for using job objects ;)
Assuming the process that you're running isn't spawning the cloned version of itself in such a way that it breaks out of the job...
You should be able to simply monitor the job events and act on JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
(see JOBOBJECT_ASSOCIATE_COMPLETION_PORT and SetInformationJobObject()). Monitoring the job in this way will also give you notifications of the processId's of new processes created within the job and details of when they exit.
Related Topics
Why Is It Allowed to Pass R-Values by Const Reference But Not by Normal Reference
How to Use Createfile, But Force the Handle into a Std::Ofstream
What Is the Printf Format Specifier for Bool
When and How to Use Gcc's Stack Protection Feature
Case Insensitive Std::String.Find()
How to Set a Timeout on Blocking Sockets in Boost Asio
What Is a Copy Constructor in C++
How to Build and Use Google Tensorflow C++ API
"Relocation R_X86_64_32S Against " Linking Error
Performance of Unsigned VS Signed Integers
How to Run a Child Process That Requires Elevation and Wait
Are Memory Leaks "Undefined Behavior" Class Problem in C++
How to Know Which Parts in the Code Are Never Used
Installing C++ Libraries on Os X
Does Std::List::Remove Method Call Destructor of Each Removed Element
How to Use Polymorphic Attributes with Boost::Spirit::Qi Parsers
When Would Anyone Use a Union? Is It a Remnant from the C-Only Days