UI Custom Action Guidelines

Windows Installer provides a rich set of standard actions that handle the typical needs of an installation: installing files and folders, manipulating the registry, searching for existing resources in the registry or the file system, controlling Windows services and so-on. Custom actions are handy things for when you need to do some custom processing that isn’t covered by one of the standard actions. You can customize your UI experience by invoking an action when the user interacts with a control by publishing a DoAction control event for the control. This post describes some guidelines (and one workaround) for custom actions invoked by the user interface in a Windows Installer MSI package.

Prefer Standard Actions For Standard Tasks

Familiarize yourself with the standard actions and the tasks they perform. Writing a custom action is not trivial and requires good testing in all the installation scenarios in order to make sure that you’ve got your custom action implemented properly. Avoid writing a custom action if you can by exploiting the existing behavior of standard actions. A custom action is almost never needed to manipulate the registry, the file system or Windows services.

All User Interface Custom Actions Are Immediate

A custom action used in your user interface must be scheduled for immediate execution. Typically you will also want these custom actions to be synchronous so that event processing continues after the action completes. See the Windows Installer documentation on the in-script execution options for the specifics.

In WiX, an immediate synchronous custom action is defined with the following markup:

<CustomAction Id="rtGetWMIProperties"
              Execute="immediate" Return="check"

This particular custom action is implemented by a JScript file in the binary table.

Don’t Modify the System

First, custom actions in the user interface should never modify the system. The user interface should be used to gather information that configures system modifications, not modify the system directly. Users expect that they can invoke an installer package with a reduced or minimal user interface and configure the package using the defaults or by setting public properties from the command-line. If your user interface modifies the system and your interface is reduced, then the modification will not take place because your UI won’t be exposed.

If you need to modify the system, split that modification into two parts. First, gather and validate information from the user and store that information in public properties. Second, use the information from the public properties to modify the system in a deferred execution custom action that is sequenced in the install transaction. If your user interface is reduced, the system modification can still be configured through the use of the public properties.

Create Accounts With Needed Permissions Instead of Asking for Credentials

Sometimes an application will need specific permissions in order to perform its function. This scenario has come up on the WiX user’s mailing list on several occasions where people ask how to create a custom action that validates the entered credentials. This is not a good approach to the problem. First, users and administrators are skeptical of installations that request credentials to be entered at installation time, particularly when the request is for credentials with permissions beyond those of an ordinary user. Second, its entirely unnecessary to ask for priveleged credentials in order to create an environment where your application executes with sufficient priveleges to perform its requested function.

A better approach is to identify the minimum set of rights and priveleges needed by your application in order to perform its function and create a new account and/or group on the target machine having those rights priveleges and no more. Create the account without interactive login rights. You can remove the group or account when your application is removed. The full details of this approach warrant a blog post by itself, but if you need to pursue this strategy, I recommend Keith Brown’s book Programming Windows Security. It will explain the Windows security model so that you can understand the minimum security requirements for your application.

A Workaround for Custom Actions That Set Properties

Windows Installer appears to build a script for each user interface control before it executes any of the actions associated with the control. When you invoke a user interface custom action that sets properties and subsequent control events use the properties, Windows Installer appears to ignore the changed property values in the events executed after the custom action. A simple workaround to compensate for this behavior is to insert a set property control event that sets the property to its current value. This is accomplished in WiX with the following markup:

<Publish Dialog="SomeDialog" Control="Next"
         Event="DoAction" Value="rtGetWMIProperties"
<Publish Dialog="SomeDialog" Control="Next"
         Property="FoundWMI" Value="[FoundWMI]"
<Publish Dialog="SomeDialog" Control="Next"
         Property="SomeDialog_Next" Value="{}"
<Publish Dialog="SomeDialog" Control="Next"
         Property="SomeDialog_Next" Value="FoundWMIDialog"
         Order="4">FoundWMI = 1</Publish>
<Publish Dialog="SomeDialog" Control="Next"
         Property="SomeDialog_Next" Value="WMINotFoundDialog"
         Order="5">NOT SomeDialog_Next</Publish>
<Publish Dialog="SomeDialog" Control="Next"
         Event="NewDialog" Value="[SomeDialog_Next]"

In this markup, first a custom action is called that sets the FoundWMI property. We immediately set this property to its current value to workaround Windows Installer not recognizing that the property has changed. Subsequent control events use the property in a branching Wizard dialog sequence to navigate to the next dialog based on the value of the property.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: