C# – Correct way to deal with UAC in C#

cnetuac

I have an application (Windows service) that is installed into a directory in the Program Files folder. Alongside this application is another WinForms application that is used to configure the service (amongst other things). When it does configuration, it saves changes to a config file that lives alongside the service.

When running on Vista/Win7, UAC prevents the user from saving to the config file. What I would like to do is:

  • put the shield icon next to the menu item used to configure
  • prompt for UAC permissions when this item is chosen
  • only show the icon/prompt when on an OS that requires it
  • only show the icon/prompt when permissions are required (eg. if the application is installed somewhere that does not require UAC permission)

I don't really want to run the whole application as an administrator, as it is also used for other purposes that do not require UAC permissions (so setting an application manifest file is not the correct solution). I'm also assuming (correct me if I'm wrong) that once UAC permissions have been granted, my existing process cannot perform the action and that I will need to start a new process.

How can I best achieve this?

Best Answer

This is fairly easy. Put a shield icon on the button that saves changes to the configuration file, instead of the menu item. This follows the Windows behavior of not requesting UAC permissions until the last moment. The button actually will launch your executable again as administrator with a special command line (that you decide) to perform the configuration file saving. Use a named pipe (be sure to give it the correct permissions) to pass the configuration data to your second instance if your don't want to use the command line for data passing.

For launching your executable:

ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "YOUR EXE";
info.UseShellExecute = true;
info.Verb = "runas"; // Provides Run as Administrator
info.Arguments = "YOUR SPECIAL COMMAND LINE";

if (Process.Start(info) != null)
{ 
    // The user accepted the UAC prompt.
}

This works also when UAC doesn't exist (Windows XP), because it will simply run as administrator if possible, or prompt for credentials. You can check whether the OS requires UAC by simply doing Environment.OSVersion.Version.Major == 6. 6 is both Windows Vista and 7. You can make sure you're using Windows by looking at Environment.OSVersion.Platform.

For detecting whether you're application is already admin, you can do this:

public static bool IsAdministrator()
{
    WindowsIdentity identity = WindowsIdentity.GetCurrent();

    if (identity != null)
    {
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        return principal.IsInRole(WindowsBuiltInRole.Administrator);
    }

    return false;
}