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:

8 Comments

  • https://secure.gravatar.com/avatar/0b7a7d461c8249fb127a418f278d3ac0?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Ian Crane says:

    What if you only update the contents of readme.txt? Will it just overwrite it or do you have to remove and add it?

  • https://secure.gravatar.com/avatar/e1a4c2b21a5186e0b27c1c601f418b76?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Pieter van der Westhuizen says:

    Hi Ian,

    You would still need to update the version number of the application in order for the installer to upgrade the old version.

  • This works great, however, the setup still asks me for the target directory. How would you skip InstallDirDlg during a major update? I tried different customizations of WixUI_InstallDir, but I’m not experienced enough to get it right. Even http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Hide-InstallDirDlg-during-upgrade-td5014310.html did not help me.

  • https://secure.gravatar.com/avatar/e1a4c2b21a5186e0b27c1c601f418b76?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Pieter van der Westhuizen says:

    Hi Thomas,

    Thanks for reading! Have you tried setting the UIRef element to WixUI_Minimal? For example:
    <UIRef Id="WixUI_Minimal" />

    It is one of the built-in Wix dialogs.

    Hope this help! :)

  • I tried to customize the UI sequence already. However, I never managed to get the conditions right, when to switch to what dialog.

  • https://secure.gravatar.com/avatar/e1a4c2b21a5186e0b27c1c601f418b76?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Pieter van der Westhuizen says:

    Hi Thomas,

    I had a quick read of the link you posted.
    Now, I have not tested this myself yet, but it looks like you can set conditions on when to hide/show dialogs.

    Maybe try something like the following:
    <UIRef Id=”WixUI_Minimal” />

    <Publish Dialog=”WixUI_InstallDir” Control=”Back” Event=”NewDialog” Value=”WixUI_InstallDir”
    Order=”4″>NOT Installed</Publish>

    Far as I understand this will only show the InstallDir dialog if the product is not installed.
    As I’ve said I’ve not tested this myself, but it wont hurt to give it a shot :)

  • I noticed that in the ‘Assembly Information’ dialog in this example there was a GUID value.

    When I bring mine up, no GUID value is present. Is this why I’m getting the “Newer Version Already Installed” message?

    Steps I take to create an installer.
    1) Make the usual code updates to my Add-In
    2) Update the version number (e.g. 1.0.10016 to 1.0.10017)
    3) I leave the “*” alone. I do not create a GUID
    4) I compile the Setup project then try running it on my test machine that has the previous version of the Add-In installed.

  • https://secure.gravatar.com/avatar/e1a4c2b21a5186e0b27c1c601f418b76?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Pieter van der Westhuizen says:

    Hi Germán,

    Make sure you also incrementthe version number in the .wxs file:
    <Product Id="*" Name="Win App" Language="1033" Version="2.0.0.0"

    I've followed your steps and also incremented the version number in the .wxs file and it installed without a problem.

    Hope this helps!

Post a comment

Have any questions? Ask us right now!