Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Creating an installer using Wix v3.0, Votive, and Visual Studio 2005/2008 - Part 2, the GUI

4.85/5 (58 votes)
28 Nov 2007CPL11 min read 3   2K  
An introduction to creating a Wix installer with GUI using Visual Studio 2005/2008.

Introduction

We have already seen how to create a basic installer using Wix, but to the end user, the results weren't spectacular. A small box with a title and a progress bar were all we had to show for our work. In this article, we will cover adding a slightly more impressive GUI to the installer. This section will cover the inbuilt GUI capabilities of Wix. One of the great strengths of Wix is its extensibility, and this is particularly true of the GUI. Such extensibility is, however, beyond the scope of this article.

Prerequisites

It is assumed that you have followed the steps of the first article in this series. This article builds on the project from the first article, so you should obtain a copy if you plan to follow along. The prerequisites of the first article (Wix, Visual Studio with the Votive plug-in installed) are also required for this article.

Getting Started

We have our Windows Forms application, and we have our Wix project. At the moment, the installer provides no mechanism for user interactivity. In order to provide this, we will add a GUI to the installer.

Extra capabilities are provided by assemblies that are installed with Wix. In order to make use of them, we must add a reference to the appropriate assembly to our Wix project. Select the ExampleInstaller project file in Solution Explorer, and then click Project --> Add Reference. The following dialog box will appear:

Screenshot - addReference.png

The assembly that we want is called WixUIExtension.dll. It will be located in the same directory in which you installed Wix.

Highlight this assembly, click Add, and then click OK. This adds the UI extensions to your Wix project. We can now add UI capability to our Installer. To do this, we add the element <UIRef> as a child of our <Product> element. The <UIRef> element has a single attribute, Id, and the value assigned to this attribute controls the style of the GUI that is produced. The possible values for the attribute are (in ascending order of complexity):

  • WixUI_Minimal
  • WixUi_InstallDir
  • WixUI_FeatureTree
  • WixUI_Mondo

We'll run through the GUI types and examine what you get with each one.

WixUI_Minimal

As one can infer from the value, this is the most minimal setting available for the UIRef ID attribute. We add <UIRef Id="WixUI_Minimal"/> to our wxs file. Our wxs file now looks like this:

XML
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
   Name="Wix installer walkthrough" 
   Language="1033" Version="1.0.0.0" Manufacturer="Duncan Lundie" 
   UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File d="InstallationTarget.exe"
         Source="../InstallationTarget/InstallationTarget/bin/
                $(var.BUILD)/InstallationTarget.exe">
      </File>
     </Component>
    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" Level="1">
   <ComponentRef Id="ProductComponent" />
  </Feature>
        
  <UIRef Id="WixUI_Minimal"/>
  </Product>
</Wix>

We can now try building the installer to see what the results look like. Unfortunately, at this point, the build fails with an intimidating 207 error. Don't panic! All of these errors spring from the same root cause, namely that we have not set a localization Culture for the project. While we were not making use of the GUI, this was not an issue, but the GUI extension requires that the Culture be set. This is done on the Linker tab of the Wix project property page. It seems that the only English culture currently supported is en-US (US English), so this is the value that we'll put in the Cultures textbox. Multiple values may be added here, separated by semicolons. If you remember from the previous article, these settings are per-configuration, and must be added for each build configuration. Once we have added the appropriate Cultures, we can try building the project again. If we've done everything correctly, the project should build successfully.

We can now run our minimal GUI installer, and we should see this:

Screenshot - minimalStart.png

The installer displays the Common Public License 1.0, by default. Later, we'll see how we can change this. When we check to accept the terms of the License and click Install, the next window appears:

Screenshot - minimalMiddle.png

When it's finished, we see the final confirmation screen:

Screenshot - minimalFinish.png

And, we click Finish to complete the installation.

As you can see, WixUI_Minimal lives up to its name. It's an improvement over the non-GUI installer, and if you don't want to allow your users any customization of the install, it's fine. If this isn't the case, then we need something a little more interactive.

WixUi_InstallDir

This attribute value allows the user to select the directory into which your application will be installed. In order to make use of this GUI type, we first need to make some tweaks to the wxs file to let the installer know which directory it is customizing.

We add an element to the wxs file, of type <Property>; this element has two attributes: an Id, which we set to "WIXUI_INSTALLDIR", and a Value which we set to "INSTALLLOCATION". The WIXUI_INSTALLDIR Id lets Wix know that this property will tell it what directory to install into. The INSTALLLOCATION value lets the installer know which directory we are defaulting to (the path we set up with our nested <directory> elements) and the contents of that directory (in this case, the component containing our application). Our wxs file should now look like this:

XML
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
    Name="Wix installer walkthrough" 
    Language="1033" Version="1.0.0.0" 
    Manufacturer="Duncan Lundie" 
    UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File Id="InstallationTarget.exe" 
        Source="../InstallationTarget/InstallationTarget/bin/
                $(var.BUILD)/InstallationTarget.exe">
      </File>
     </Component>

    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" Level="1">
   <ComponentRef Id="ProductComponent" />
  </Feature>

   <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" ></Property>
  <UIRef Id="WixUI_InstallDir"/>
        
 </Product>
</Wix>

We can now build our installer and see how the changes we have made have influenced the look and feel of our GUI.

Screenshot - installdirFirst.png

Screenshot - installDirSecond.png

Screenshot - installDirThird.png

This is the first major difference from the minimal GUI – our default install location is displayed, along with the option to change the directory (or type in a new one). If we select change, we see this:

Screenshot - installDirChange.png

We can then change the installation directory:

Screenshot - installDirChanged.png

And now, finish the installer.

The final two forms are the same as that of the minimal installer. If you now check the installation directory you specified in the dialog, you should see a copy of our example installation target.

WixUI_FeatureTree

Both WixUI_FeatureTree and WixUI_Mondo are GUI options that are designed to allow users to customize the features that are installed when the package runs. Our installer only contains one feature, so there won't be a lot of choices, but we can at least demonstrate the principle.

To use WixUI_FeatureTree, we need to configure the features that we are offering. The features can be installed, or not, as chosen by the user, so rather than defining an installation directory property, we add a configurable directory attribute to the feature definition. This allows the user to customize the installation directory for each feature.

Our wxs file now looks like this:

XML
  <?xml version="1.0" encoding="UTF-8"?>
  <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
     Name="Wix installer walkthrough" Language="1033" 
     Version="1.0.0.0" Manufacturer="Duncan Lundie" 
     UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File Id="InstallationTarget.exe" 
        Source="../InstallationTarget/InstallationTarget/bin/
               $(var.BUILD)/InstallationTarget.exe"></File>
     </Component>

    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" 
          Level="1" ConfigurableDirectory="INSTALLLOCATION">
   <ComponentRef Id="ProductComponent" />
  </Feature>

  <UIRef Id="WixUI_FeatureTree"/>
        
 </Product>
</Wix>

We have added the ConfigurableDirectory attribute to our feature, and set its value to "INSTALLLOCATION", which is the identifier for the installation directory we have described in our nested <Directory> elements. Now, when we build the installer, we will be offered the opportunity to customize where this feature is installed. We can try this out now.

The first two forms are familiar to us from the InstallDir setting.

Screenshot - installdirFirst.png

Screenshot - installDirSecond.png

The third form is where things become more interesting:

Screenshot - featureTree.png

The feature that we defined in our wxs file has become a configurable element within our installer, and the title that we have assigned it is its label. From this screen, we can configure the installation directory, and even whether or not to install the feature.

Screenshot - featureChoices.png

Multiple Features

This GUI setting is all very well, but rather meaningless without some other features to demonstrate its capabilities. In this instance, we'll simply add some dummy text files to the project and then define them as features.

So, to add the files, right-click the InstallationTarget project file, and select Add New Item, change to the General category (VS2008), and select Text file. Rename it to subfeature1.txt. Follow this procedure three more times, so that we end up with subfeature1.txt, subfeature2.txt, subfeature3.txt, and subfeature4.txt.

We now need to define a component for each of our subfeatures. Remember that a feature must have at least one component. We will place our subfeatures in the same directory as our main installation target, although we could quite easily define subdirectories, should we so wish.

We add code to the wxs file so that it now looks like this:

XML
<?xml version="1.0" encoding="UTF-8"?>
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="07cdd126-8d87-46cf-87b0-8731980619fa" 
    Name="Wix installer walkthrough" Language="1033" 
    Version="1.0.0.0" Manufacturer="Duncan Lundie" 
    UpgradeCode="4b2952e6-8ce6-4254-9796-aa510afe5fc0">
  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="ExampleInstaller.cab" EmbedCab="yes" />

  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Installer Example">

     <Component Id="ProductComponent" Guid="17e13748-8d44-47f6-b020-66d29f8a84fe">
      <File Id="InstallationTarget.exe" 
         Source="../InstallationTarget/InstallationTarget/bin/
                $(var.BUILD)/InstallationTarget.exe"></File>
     </Component>
     <Component Id="SubComponent1" 
        Guid="0B01C426-7562-4073-833B-265EE4A31FCD">
      <File Id="Subfeature1.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature1.txt"></File>
     </Component>
     <Component Id="SubComponent2" Guid="C481566D-4CA8-4b10-B08D-EF29ACDC10B5">
      <File Id="Subfeature2.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature2.txt">
      </File>
     </Component>
     <Component Id="SubComponent3" Guid="44E233A0-CDA2-4adf-B2AF-935A0174325B">
      <File Id="Subfeature3.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature3.txt">
      </File>
     </Component>
     <Component Id="SubComponent4" Guid="7F75F6A5-3F09-4921-96F3-D8019FD3954B">
      <File Id="Subfeature4.txt" 
        Source="../InstallationTarget/InstallationTarget/Subfeature4.txt">
      </File>
     </Component>
    </Directory>
   </Directory>
  </Directory>

  <Feature Id="ProductFeature" Title="Installation Target" Level="1" 
         ConfigurableDirectory="INSTALLLOCATION" TypicalDefault="install" >
   <ComponentRef Id="ProductComponent" />
   <Feature Id="SubFeature1" Title="First Subfeature" Level="1" >
    <ComponentRef Id="SubComponent1"/>
    </Feature>
   <Feature Id="SubFeature2" Title="Second Subfeature" Level="1" >
    <ComponentRef Id="SubComponent2"/>
   </Feature>
   <Feature Id="SubFeature3" Title="Third Subfeature" Level="1" >
    <ComponentRef Id="SubComponent3"/>
   </Feature>
   <Feature Id="SubFeature4" Title="FourthSubfeature" Level="1" >
    <ComponentRef Id="SubComponent4"/>
   </Feature>
  </Feature>
</Wix>

Build the Wix project. Now, during the installation process, the feature tree will look like this:

Screenshot - featuretreenested.png

The subfeatures have been nested under the original feature, and can be selected for installation individually or as a group. Try this out, and you will see that only the selected subfeatures (i.e., the text files) get placed in your installation directory. You might also notice that you cannot modify the install location for the subfeature, only the parent.

WixUI_Mondo

This is the "everything" choice for a Wix GUI, and includes elements from the FeatureTree choice, plus an extra form which gives the user a choice of install types –Custom, Typical, and Complete. The form looks like this:

Screenshot - mondo.png

Selecting Typical or Complete will begin the installation, accepting the default install location and (at the moment) installing all the available features. Choosing custom will bring us to the same form as is displayed in the FeatureTree section.

Defining a Typical Setup

As it stands, a "typical" setup from our installer is identical to a complete setup. To make the differentiation meaningful, we must define which features are to be considered "typical". We do this by making use of the INSTALLLEVEL property.

INSTALLLEVEL is an internal value of the Windows installer, rather than being a part of Wix. It is an integer value. Each feature defined in our wxs file has a Level attribute, also an integer. A feature will be installed when its level is less than or equal to the INSTALLLEVEL.

By default, the INSTALLLEVEL is 1. When using WixUI_Mondo, clicking the Typical button sets the INSTALLLEVEL value to 3. Conversely, clicking Complete sets INSTALLLEVEL to 1000.

This lets us define what Typical is by changing the Level variable of the features we wish to include to less than or equal to 3, and those we wish to exclude to greater than 3.

Let's say that we're biased against odd numbers. We set the Level attribute on SubFeature1 and SubFeature3 to be 4.

XML
 <Feature Id="ProductFeature" Title="Installation Target" Level="1"
  ConfigurableDirectory="INSTALLLOCATION" TypicalDefault="install" >
 <ComponentRef Id="ProductComponent" />
 <Feature Id="SubFeature1" Title="First Subfeature" Level="4" >
  <ComponentRef Id="SubComponent1"/>
 </Feature>
 <Feature Id="SubFeature2" Title="Second Subfeature" Level="1" >
  <ComponentRef Id="SubComponent2"/>
 </Feature>
 <Feature Id="SubFeature3" Title="Third Subfeature" Level="4" >
  <ComponentRef Id="SubComponent3"/>
 </Feature>
 <Feature Id="SubFeature4" Title="FourthSubfeature" Level="1">
  <ComponentRef Id="SubComponent4"/>
 </Feature>
</Feature>

Now, when we build the project, our Typical installation will not include subfeatures 1 or 3.

When to Use GUI Types

The decision of which GUI type to use should rest on the level of customization you wish to allow to the end user.

  • If you don't want any customization, but still want the GUI to display a license agreement, then you would choose WixUI_Minimal.
  • If all you want to allow your user to do is change the installation directory, choose WixUI_InstallDir.
  • If your product installs all features by default, but you want your user to have the option of disabling some, you would choose WixUI_FeatureTree.
  • If some of the features of your product are disabled, by default, and you want your user to have the ability to customize the features that are installed, you would choose WixUI_Mondo.

Customizing the Stock GUI

Changing the functionality of the stock GUIs is beyond the scope of this article. We can, however, alter the look and feel of the GUI in a number of ways.

Remember to add any variable definition to all of your build configurations, as Wix has separate variables for each configuration. Variables are separated with a semicolon.

License

Unless you plan on releasing all your software under the Common Public License, one of the first things you'll want to change is the license text.

The first step is to create an RTF document containing the text of the license you wish to use. Never one to shy away from controversy, I have selected the GLP v3. Do not use Word to create the RTF (use Wordpad), as Wix seems to have problems reading Word RTF files (the license area is left blank).

Once you have created the RTF document, save it as GPL3.rtf and add it to your Wix project.

Now, we must tell Wix where to look for its new license text. In the Linker tab of the Wix project properties, add the text WixUILicenseRtf=GPL3.rtf to the "Define Wix variables" field. This variable tells Wix where to look for the RTF file. The build will fail if the file cannot be found.

Start and Finished Form Backgrounds

In much the same way as the license text, we can change the background of the GUI start and finish forms by adding a new file. The file should be a bitmap, with dimensions of 493px X 312px. I've called mine bigback.bmp. You can't alter the layout of the text in this instance, so I recommend leaving the right hand side of the image clear of anything that might interfere with legibility.

Add the bitmap to your project, then set the variable WixUIDialogBmp=bigback.bmp. Rebuild your installer, and the background image should have changed to the bitmap you specified.

Screenshot - customisedInstaller.png

Top Banner

The file for this should be a bitmap, 493 x 58px. I've called mine banner.bmp. The variable setting for it is WixUIBannerBmp.

Screenshot - custombanner.png

License

This article, along with any associated source code and files, is licensed under The Common Public License Version 1.0 (CPL)