Step 3: Redesign for UAC Compatibility (UAC)

Step Three: Redesign Your Application's Functionality for UAC Compatibility

Use the information in this section once you have classified your application and determined whether it must be redesigned for UAC.

Windows Vista Application Run-time Requirements

A large component of redesigning your application for Windows Vista® will be examining your application's user access model at its core.

Requirements for All Windows Vista Applications

Specify a requestedExecutionLevel

For UAC to operate properly, the operating system has to be able to identify what code needs elevated privilege and what code does not.

In Windows Vista, these changes require that applications be marked with information that allows the operating system to determine in what context the application should be launched. For example, standard user applications need to be marked to run as the invoker and accessibility-enabled applications need to be identified by the system.

Do Not Register Components with Rundll32

Some applications use the Windows Rundll32 executables to run components. However, this method is not compliant with Windows Vista development requirements. Calling directly into Rundll32 results in UAC compatibility issues. When an application relies on the Rundll32 executables to perform its execution, Rundll32 calls AIS on behalf of the application to initiate the UAC elevation prompt. As a result, the UAC elevation prompt has no knowledge of the original application and displays the application requesting elevation as "Windows host process(Rundll32)." Without a clear description and icon for the application requesting elevation, users have no way to identify the application and determine whether it is safe to elevate it.

If your application calls into Rundll32 to run components, use the following workflow to redesign the execution call.

  1. Create a new separate executable file for your application.

  2. In the new executable file, call the exported function in your DLL that you would have specified with Rundll32. You may need to LoadLibrary the DLL if it does not have a .lib.

  3. In a resource file, create and add a new icon for the executable. This icon will be displayed in the User Account Control dialog box when the application requests elevation.

  4. Provide a short, meaningful name for the executable. This name will be shown in the User Account Control dialog box when the application requests elevation.

  5. Create and embed an application manifest file for the executable and mark it with the requested execution level of requireAdministrator. This process is detailed in the Create and Embed an Application Manifest with Your Application section.

  6. Authenticode sign the new executable. This process is detailed in the Authenticode Sign Your Application section later in this document.

Finally, following the un-installation of an application, the user should be able to reinstall it without errors.

Requirements for Standard User Applications

Here is a summary of things to remember when designing applications that operate correctly under a standard user account. Developers should keep these requirements in mind during the design phase of their applications.

Setup

  • Never perform administrative actions (such as completing the setup process) on first run; these actions should be done as part of the initial setup process.

  • Never write directly to the Windows directory or subdirectories. Use the correct methods for installing files, such as fonts.

  • If you need to automatically update your application, use a mechanism suitable for use by standard users, such as Windows Installer 4.0 User Account Control patching to accomplish the update.

Saving State

  • Do not write per-user information or user-writable information to Program Files or Program directories.

  • Do not use hard-coded paths in the file system. Take advantage of the KnownFolders API and ShGetFolder to find where to write data.

Run and Test Under a Standard User Account

If you are writing a non-administrative application, such as a LOB application or a user application, such as a game, you must always write application data to a location that standard users can access. The following are some of the recommended requirements:

  • Write per-user data to the user profile: CSIDL_APPDATA.

  • Write per-computer data to Users\All Users\Application Data: CSIDL_COMMON_APPDATA.

  • The application cannot depend on any administrative APIs. For example, a program that expects to successfully call the SetTokenInformation() Windows function will fail under a standard user account.

Be Fast User Switching (FUS) Aware

Applications will more commonly be installed by a user other than the user who will run the application. For example, in the home, this means that a parent will install the application for a child. In the enterprise, a deployment system, such as SMS or Group Policy advertisement, will install the application using an administrator account.

If the per-user settings do not exist at first run, rebuild them. Do not assume that the setup process took care of the settings.

Requirements for Administrator Applications

Use the HWND Property to Be Acknowledged as a Foreground Application

Background applications will automatically prompt the user for elevation on the taskbar, rather than automatically switching to the secure desktop for elevation. The elevation prompt will appear minimized on the taskbar and will blink to notify the user that an application has requested elevation. An example of a background elevation occurs when a user browses to a Web site and begins downloading an installation file. The user then goes to check e-mail while the installation downloads in the background. Once the download completes in the background and the install begins, the elevation is detected as a background task rather than a foreground task. This detection prevents the installation from abruptly stealing focus of the user's screen while the user is performing another task--reading e-mail. This behavior creates a better user experience for the elevation prompt.

However, some foreground applications currently prompt as background applications on Windows Vista. This behavior is the result of an absent parent HWND. In order to ensure that Windows Vista acknowledges your application as a foreground application, you must pass a parent HWND with a ShellExecute, CoCreateInstanceAsAdmin, or managed code call.

The UAC elevation mechanism uses the HWND as part of determining whether the elevation is a background or foreground elevation. If the application is determined to be a background application, the elevation is placed on the taskbar as a blinking button. The user must click on the button, as with any application requesting foreground access, before the elevation will continue. Not passing the HWND will result in this occurring even though the application might actually have foreground.

The following code sample illustrates how to pass HWND with ShellExecute:

BOOL RunAsAdmin( HWND hWnd, LPTSTR lpFile, LPTSTR lpParameters )
{
    SHELLEXECUTEINFO   sei;
    ZeroMemory ( &sei, sizeof(sei) );

    sei.cbSize          = sizeof(SHELLEXECUTEINFOW);
    sei.hwnd            = hWnd;
    sei.fMask           = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
    sei.lpVerb          = _TEXT("runas");
    sei.lpFile          = lpFile;
    sei.lpParameters    = lpParameters;
    sei.nShow           = SW_SHOWNORMAL;

    if ( ! ShellExecuteEx ( &sei ) )
    {
        printf( "Error: ShellExecuteEx failed 0x%x\n", GetLastError() );
        return FALSE;
    }
    return TRUE;
}

The following code sample illustrates how to pass HWND with CoCreateInstanceAsAdmin by using the elevation moniker. It assumes that you have already initialized COM on the current thread. More information about the elevation moniker is available in Step 4: Redesign Your UI for UAC Compatibility of this document.

HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
    BIND_OPTS3 bo;
    WCHAR  wszCLSID[50];
    WCHAR  wszMonikerName[300];

    StringFromGUID2(rclsid, wszCLSID,   
                    sizeof(wszCLSID)/sizeof(wszCLSID[0])); 
    HRESULT hr = StringCchPrintf(wszMonikerName,  
                      sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
    if (FAILED(hr))
        return hr;
    memset(&bo, 0, sizeof(bo));
    bo.cbStruct = sizeof(bo);
    bo.hwnd = hwnd;
    bo.dwClassContext  = CLSCTX_LOCAL_SERVER;
    return CoGetObject(wszMonikerName, &bo, riid, ppv);
}

BIND_OPTS3 is new in Windows Vista. It is derived from BIND_OPTS2. It is defined as follows:

typedef struct tagBIND_OPTS3 : tagBIND_OPTS2
{
    HWND hwnd;
} BIND_OPTS3, * LPBIND_OPTS3;

The only addition is an HWND field, hwnd. This handle represents a window that becomes the owner of the elevation UI when secure desktop prompting is enabled.

The following code sample illustrates how to pass HWND in managed code to ensure that parent dialogs are aware of the HWND and its use.

System.Diagnostics.Process newProcess = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo("D:\SomeProgram.exe");
info.UseShellExecute = true;
info.ErrorDialog = true;
info.ErrorDialogParentHandle = this.Handle;
newProcess.StartInfo = info;
newProcess.Start();

Do Not Prompt for Elevation in the User's Logon Path

Applications that start when the user logs on and require elevation are now blocked in the logon path. Without blocking applications from prompting for elevation in the user's log on path, both standard users and administrators would have to respond to a User Account Control dialog box on every log on. Windows Vista notifies the user if an application has been blocked by placing an icon in the system tray. The user can then right-click this icon to run applications that were blocked from prompting for elevation as the user logged on. In addition, the user can manage which startup applications are disabled or removed from this list by double-clicking on the tray icon.

Do Not Use Runas to Launch an Elevated Process

The Run as… option from Windows XP and Windows Server 2003 has been replaced with Run as administrator on the context menu (available when you right-click an executable) in Windows Vista. When a standard user selects the Run as administrator option, the user is presented with a list of active administrators on the local computer. Standard users with higher privileges, such as members of the Backup Operators group, are also displayed. When an administrator selects the Run as administrator option, a User Account Control dialog box immediately prompts the user to continue before running the application.

Users must use the runas command at the command prompt in order to run an application as another user.

Important

Be aware that runas does not provide the ability to launch an application with an elevated access token, regardless of whether it is a standard user with privileges like a Backup Operator or an administrator. The runas command grants the user the ability to launch an application with different credentials. The best method to use to launch an application with a different account is to perform the action programmatically by using a service and not rely on the user to run the component as a different user. If your program programmatically uses the runas command, ensure that it is not intended to launch an elevated process.

If your application will require the user to run parts of the application with a different user account, ensure that the runas command with the command prompt option is exposed. The following table details the available parameters for the runas command.

Runas parameters

Parameter

Description

/noprofile

Specifies that the user's profile should not be loaded. This enables the application to load more quickly, but can cause some applications to malfunction.

/profile

Specifies that the user's profile should be loaded. This is the default setting.

/env

Use the current environment instead of the user's.

/netonly

Use this parameter if the credentials specified are for remote access only.

/savecred

Use credentials previously saved by the user. This option is not available on Windows XP, Home Edition, and will be ignored.

/smartcard

Use this parameter if the credentials to be provided are from a smart card.

/user

The user's user name. The user name should be provided in the form of USER\DOMAIN or USER@DOMAIN.

/showtrustlevels

Displays the trustlevels that can be used as arguments for the /trustlevel parameter.

/trustlevel

One of the levels enumerated in /showtrustlevels.

program

Command line for an executable.

Examples:

runas /noprofile /user:mymachine\Denise cmd

Note

Enter the user's password only when prompted. The /profile parameter is not compatible with the /netonly parameter. The /savecred parameter is not compatible with the /smartcard parameter.

Requirements for Console Applications

A console application presents its output on the console window and not with a separate user interface. If an application needs a full administrator access token to run, then that application needs to be launched from an elevated console window.

You must do the following for console applications:

  1. Mark that your application "asInvoker": You can do this by authoring the manifest of your application in which you set RequestedExecutionLevel == asInvoker. This setup allows callers from non-elevated contexts to create your process, which allows them to proceed to step 2.

  2. Provide an error message if application is run without a full administrator access token: If the application is launched in a non-elevated console, your application should give a brief message and exit. The recommended message is:

    • "Access Denied. Administrator permissions are needed to use the selected options. Use an administrator command prompt to complete these tasks."

The application should also return the error code ERROR_ELEVATION_REQUIRED upon failure to launch to facilitate scripting.

Requirements for Scripts

Scripts may be considered as a group of applications run in a predefined order and the results of one being channeled into other.

In order to make your scripts UAC compliant, examine the logic of your scripts and add "tests" to ensure the person running the script has sufficient privileges to do that task. This check should be done before performing an action in the script.

Requirements for Bulk Operations

If your application performs a task that consists of actions on multiple objects, and some of them might require the user's administrator access token, then show the elevation prompt the first time the access token is needed. If the user approves the elevation, then perform the rest of the tasks. Otherwise, terminate the batch operation. This behavior would be consistent with the current multi-select/copy/delete operation.

APIs That Help Identify an Administrator

  • IsUserAnAdmin()

  • GetTokenInformation()

Registry/Handle Access Permissions That Are Inherently Different Between Administrators and Standard Users

  • MAXIMUM_ALLOWED

  • KEY_WRITE

  • DELETE (when applied to registry keys)

  • Other HKLM-like keywords (opened with MAXIMUM_ALLOWED on XP):

  • SHELLKEY_HKLM_EXPLORER

  • SHELLKEY_HKLM_SHELL

Other APIs That Are Redirected to HKLM Registry Values and Virtualization Will Apply

  • WritePrivateProfileString(,,,"system.ini");

  • CheckSectionAccess("system.ini",…);

See Also

Concepts

Designing UAC Applications for Windows Vista