Launch elevated and modal too

Fri, December 15, 2006, 01:22 AM under Windows | Vista | UAC
Those of you that have attended my talks on UAC will have seen the demo where we extract a process and run it elevated (i.e. an elevation prompt requires the consent of the user). Here I want to add some extra juice to that one.

For the rest of you, basically, if you have some admin task in your application that you cannot redesign (i.e. get rid of), you still should not mandate that your whole application runs elevated (i.e. requires admin privileges). Instead, you should refactor that functionality in a separate process. When you require the use of that admin functionality from your main application, launch the other process elevated to do the work for you. There are a few ways you can launch the application elevated but the best one in this case is to manifest the application. An example of a manifest is here; change the level from asInvoker to requireAdministrator. Embed it in your project by pasting the following line in the “Post-build event command line” textbox of the project properties:
"$(DevEnvDir)..\..\Common7\Tools\Bin\mt.exe" -manifest "$(ProjectDir)$(TargetName).exe.manifest" –outputresource:"$(TargetDir)$(TargetFileName)";#1

So what is the extra juice I want to add in this post? Well there are two things that were nagging me with the way I showed how to launch the process.

One was that the UAC consent dialog that comes up was not modal to the main application (since it was being launched for another application). By default you do not observe this but since in my setup I have disabled the policy “Switch to the secure desktop when prompting for elevation”, it affects me [NOTE: I do not recommend you disable that policy, it just happens that I have it like that for historical irrelevant reasons]. I was tipped-off that to make the UAC dialog modal, you must pass to the ShellExecute call the handle of the main app.

The other thing I didn’t like was that if the process we launch elevated has its own UI, then that is also not modal to the application.

So here is the code that addresses both of the issues above:
private void LaunchElevatedProcess()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true; // default, but be explicit
startInfo.WorkingDirectory = Environment.CurrentDirectory; //or other if you prefer
startInfo.FileName = @"some_path_to.exe";

//// if the other process did not have a manifest
//// then force it to run elevated
//startInfo.Verb = "runas";

// Two lines below make the UAC dialog modal to this app
startInfo.ErrorDialog = true;
startInfo.ErrorDialogParentHandle = this.Handle;


try
{
Process p = Process.Start(startInfo);

// block this UI until the launched process exits
// I.e. make it modal
p.WaitForExit();

}
catch(Exception ex)
{
// user cancelled
MessageBox.Show(ex.Message, "caught it!"); //for demo purposes
return;
}
}

Enjoy :)