Pieter van der Westhuizen

How to implement a WiX installer upgrade

So by now, I hope we all know and have come to accept the fact that Visual Studio setup projects are a thing of the past and that we’ve all become comfortable with using the WiX toolset to build our Windows Installers.

But, building a WiX setup project is one thing, upgrading it is another. I’m sure many of you have encountered this dreaded message before:

“Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs on the Control Panel”

Error message: Another version of this product is already installed.

With the latest version of the WiX toolset, the default Product.wxs template helps you to avoid the above mentioned error, but for the sake of clarity we’ll illustrate why this error happens before we get into how to avoid it.

  • Building the application
  • Building the WiX setup project
  • Creating a WiX upgrade

Building the application

The sample application, which we need to deploy to the end-user, will be a very simple Windows form application that displays a Calendar control and a button. When the user clicks the button a message will display the selected date. The link label at the bottom of the form, will display help information contained in a ReadMe.txt file.

A simple Windows form application that displays a Calendar control and a button.

Building the WiX setup project

Start by creating a new Windows Installer XML Setup Project in Visual Studio. If you do not see the project templates, you probably do not have the WiX toolset installed. Head over to http://wixtoolset.org/ in order to download and install it.

Building the WiX setup project

The project template will create a boilerplate WiX setup file (Product.wxs) for you. The first thing you need to notice is that the Id attribute’s value is set to an asterisk (*) :

<Product Id="*"

It is important to keep this value an asterisk, if you set it to a GUID, you will run into problems when trying to upgrade your WiX setup project. The error message, mentioned above, will be one of them.

Add the following to the Product element:

<Media Id="1" Cabinet="WinApp.cab" EmbedCab="yes" />
 
<Feature Id="Executable" Level="1">
  <ComponentRef Id="Executable" />
  <ComponentRef Id="Documentation" />
  <ComponentGroupRef Id="RegistryGroup" />
</Feature>
 
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<UIRef Id="WixUI_InstallDir" />

The full XML for the Product element should look as follows:

<Product Id="*" Name="Win App" Language="1033" Version="1.0.0.0" 
           Manufacturer="WinApp Software Inc." 
           UpgradeCode="a9b1d837-9b09-491b-bd81-b794560745a4">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
 
    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
 
    <Media Id="1" Cabinet="WinApp.cab" EmbedCab="yes" />
 
    <Feature Id="Executable" Level="1">
      <ComponentRef Id="Executable" />
      <ComponentRef Id="Documentation" />
      <ComponentGroupRef Id="RegistryGroup" />
    </Feature>
 
    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
    <UIRef Id="WixUI_InstallDir" />
 
  </Product>

In the XML above we’ve added three features: (a) to install the applications’ executable; (b) to install the applications’ help file; and (c) to create an entry in the Windows registry.

The most important element for this article is <MajorUpgrade>. This element is used to upgrade all older versions of your WiX setup. You’ll notice that it contains a DowngradeErrorMessage attribute, which is added by default and is shown when a user tries to install an older version of the .msi when an already newer version exists on the target computer. This behavior is enabled by default in order to prevent out-of-order installations.

Next, add the following below the <Product> element:

<Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLDIR" Name="Win App">
          <Component Id="Executable" Guid="7B289C8E-6F5B-4A7B-A9A1-E78A89239714">
            <File Id="WinAppExe" Name="WinApp.exe" Source="..\WinApp\bin\Debug\Winapp.exe" Vital="yes" />
            <RemoveFolder Id="INSTALLDIR" On="uninstall" />
          </Component>
          <Component Id="Documentation" Guid="E4AA4677-6DDA-4746-A956-0A636DBB2995">
            <File Id="ReadMeTxt" Name="ReadMe.txt" Source="..\WinApp\bin\Debug\ReadMe.txt" Vital="yes" />
          </Component>
        </Directory>
      </Directory>
    </Directory>
 
    <ComponentGroup Id="RegistryGroup">
      <Component Id="_69CB4E7B_273F_4510_B885_4633736280D0" Guid="2EC2BF60-997B-44BB-BA82-C5760FB48A19" Transitive="no" Directory="TARGETDIR">
        <RegistryKey Root="HKLM" Key="Software" ForceCreateOnInstall="no" ForceDeleteOnUninstall="no" />
      </Component>
      <Component Id="_A159385C_39DE_404D_833B_6F83828512C0" Guid="1D85B1A4-ABDD-4EB5-8E70-82C609462AEB" Transitive="no" Directory="TARGETDIR">
        <RegistryKey Root="HKLM" Key="Software\WinApp Software" ForceCreateOnInstall="no" ForceDeleteOnUninstall="no" />
      </Component>
      <Component Id="_AAF14A16_5774_4861_AD86_C21F01857F59" Guid="E5F8A3A2-209A-4297-8B01-F7BB4FC6603B" Transitive="no" Directory="TARGETDIR">
        <RegistryValue Root="HKLM" Key="Software\WinApp Software" Type="string" Name="License" Value="Free" />
      </Component>
    </ComponentGroup>
 
  </Fragment>

This XML is used to copy the WinApp.exe and ReadMe.txt files to the target installation folder and it will create a Windows registry entry under HKEY_LOCAL_MACHINE\Software\WinApp Software, called License, whose value will be set to 'Free’.

The full XML for the Product.wxs file follows below:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="*" Name="Win App" Language="1033" Version="1.0.0.0" Manufacturer="WinApp Software Inc." UpgradeCode="a9b1d837-9b09-491b-bd81-b794560745a4">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
 
    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed."
                  MigrateFeatures="yes" />
 
    <Media Id="1" Cabinet="WinApp.cab" EmbedCab="yes" />
 
    <Feature Id="Executable" Level="1">
      <ComponentRef Id="Executable" />
      <ComponentRef Id="Documentation" />
      <ComponentGroupRef Id="RegistryGroup" />
    </Feature>
 
    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
    <UIRef Id="WixUI_InstallDir" />
 
  </Product>
 
  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLDIR" Name="Win App">
          <Component Id="Executable" Guid="7B289C8E-6F5B-4A7B-A9A1-E78A89239714">
            <File Id="WinAppExe" Name="WinApp.exe" Source="..\WinApp\bin\Debug\Winapp.exe" Vital="yes" />
            <RemoveFolder Id="INSTALLDIR" On="uninstall" />
          </Component>
          <Component Id="Documentation" Guid="E4AA4677-6DDA-4746-A956-0A636DBB2995">
            <File Id="ReadMeTxt" Name="ReadMe.txt" Source="..\WinApp\bin\Debug\ReadMe.txt" Vital="yes" />
          </Component>
        </Directory>
      </Directory>
    </Directory>
 
    <ComponentGroup Id="RegistryGroup">
      <Component Id="_69CB4E7B_273F_4510_B885_4633736280D0" Guid="2EC2BF60-997B-44BB-BA82-C5760FB48A19" Transitive="no" Directory="TARGETDIR">
        <RegistryKey Root="HKLM" Key="Software" ForceCreateOnInstall="no" ForceDeleteOnUninstall="no" />
      </Component>
      <Component Id="_A159385C_39DE_404D_833B_6F83828512C0" Guid="1D85B1A4-ABDD-4EB5-8E70-82C609462AEB" Transitive="no" Directory="TARGETDIR">
        <RegistryKey Root="HKLM" Key="Software\WinApp Software" ForceCreateOnInstall="no" ForceDeleteOnUninstall="no" />
      </Component>
      <Component Id="_AAF14A16_5774_4861_AD86_C21F01857F59" Guid="E5F8A3A2-209A-4297-8B01-F7BB4FC6603B" Transitive="no" Directory="TARGETDIR">
        <RegistryValue Root="HKLM" Key="Software\WinApp Software" Type="string" Name="License" Value="Free" />
      </Component>
    </ComponentGroup>
 
  </Fragment>
 
</Wix>

When we build our WiX setup project, it will generate an .msi file. Run this installer and you’ll notice that the following files are deployed to C:\Program Files (x86)\Win App\:

  • ReadMe.txt; and
  • Winapp.exe.

The path might differ if you’ve selected another location during setup. If you look in the Windows Programs and Features list, you’ll also see the Win App application was listed with a version number of 1.0.0.0 and a publisher name of WinApp Software:

Version 1 of the Win App is installed

Creating a WiX upgrade

In order to create an upgrade for our WiX installer, we first need to increase the assembly version for the windows application we’ve created earlier. To do this, right-click on the project in the Visual Studio Solution Explorer window and select properties. In the properties window, on the Application tab, click on the Assembly Information button and change the version number on the Assembly Information dialog:

Changing the version number in the Assembly Information dialog

We’ll also change the next version to use a Rich Text document for the help file instead of a plain text file. So add a new file to the project called Help.rtf.

Next, open the Product.wxs file and set the Version attribute value to 2.0.0.0:

<Product Id="*" Name="Win App" Language="1033" Version="2.0.0.0" Manufacturer="WinApp Software Inc." UpgradeCode="a9b1d837-9b09-491b-bd81-b794560745a4">

Because, we’re using a new help file, we’ll want to remove the old ReadMe.txt. To do this, we’ll first remove the old Component element that adds the ReadMe.txt file and add a new Documentation component and a <RemoveFile> element to the Documentation Component e.g.:

<Component Id="Documentation" Guid="E4AA4677-6DDA-4746-A956-0A636DBB2995">
  <File Id="HelpRtf" Name="Help.rtf" Source="..\WinApp\bin\Debug\Help.rtf" Vital="yes" />
  <RemoveFile Id="RemoveReadMe" Name="ReadMe.txt" On="both"/>
</Component>

The XML above will add the new Help.rtf file and remove the old ReadMe.txt file from the target installation folder. When you build your project and run the installer, you should no longer see the ReadMe.txt file in the target installation folder and the version number of the application in Windows Programs and Features list, should have been increased:

The version number of the application is increased.

Thank you for reading. Until next time, keep coding!

Available downloads:

Sample project

You may also be interested in:

Post a comment

Have any questions? Ask us right now!