How to Run a Child Process That Requires Elevation and Wait

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:

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

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:

  1. Use ShellExecuteEx to create the child process.
  2. Arrange for ShellExecuteEx to return a process handle for the child.
  3. 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



Leave a reply



Submit