Sunday, November 21, 2010

WiX–Coming to upgrades and just copying new files

Last time I got to installing and running a windows service written in the managed code. For this session I wanted to tackle a typical upgrade scenario:

- You have an application deployed and now you want to upgrade it, let’s say with updates to the existing files plus some new content.

I was lucky to run into this how to in wix documentation. Good thing to understand is that Version, UpgradeCode and MajorUpgrade are required ingredients even for your initial package to be upgradable. So you rather don’t miss it, as MajorUpgrade is not coming inside a default template. Another small point is to remember that Product element has a sequence of a Package and then other elements, so MajorUpgrade should come some place after a Package element.

So here is the .wxs:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="B729F062-95CB-4D16-BB2C-1D114D926364" Name="StansApp"
           Language="1033" Version="1.0.2.0"
           Manufacturer="Standa" UpgradeCode="b1adfc21-927f-470a-ac87-a5019c84a253">
    <Package InstallerVersion="200" Compressed="yes"></Package>
    <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
    <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed. 
Setup will now exit." />
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLLOCATION" Name="StansApp">
          <Component Id="ProductComponent" Guid="4810c72f-cb3b-4ef5-b02e-c70a54b8b6ff">
 
            <File Id='StansAppEXE' Name='WindowsService1.exe' DiskId='1'
                Source='..\WindowsService1\bin\Debug\WindowsService1.exe'
                KeyPath='yes' />
            <File Id='StansAppConfigFile' Name='WindowsService1.exe.config' DiskId='1'
      Source='..\WindowsService1\bin\Debug\WindowsService1.exe.config' ReadOnly='no'  />
            <ServiceInstall Vital='yes' ErrorControl='ignore' Type='ownProcess'
                            DisplayName='Stans App Win Service'
                            Description='A proof of concept service' Name='StansWinService' Start='auto' />
            <ServiceControl Id='ControlStansWinService' Remove='both' Name='StansWinService'
                            Start='install' Stop='both' Wait='yes' />
          </Component>
          <Directory Id='Config' Name='Config'>
            <Component Id='ConfigComponent' Guid='266D3DA9-BBDD-44A9-B340-3AE28CF5EA0F'>
              <File Id='StansConfigFile' Name='ConfigFile.txt' DiskId='1'
        Source='..\WindowsService1\bin\Debug\Config\ConfigFile.txt' ReadOnly='no'   />
            </Component>
          </Directory>
        </Directory>
      </Directory>
    </Directory>
 
    <Feature Id="ProductFeature" Title="WinService" Level="1">
      <ComponentRef Id="ProductComponent" />
      <ComponentRef Id="ConfigComponent" />     
      <ComponentGroupRef Id="Product.Generated" />
    </Feature>
  </Product>
</Wix>

To explain the sample a bit:

  <Product Id="B729F062-95CB-4D16-BB2C-1D114D926364" Name="StansApp"
           Language="1033" Version="1.0.2.0"

Product Id has to be changed for an upgrade. Also version has to be changed at least at the third digit level. Part of the upgrade was also creating a new nested directory with name “Config” and copying a new file into it:

          <Directory Id='Config' Name='Config'>
            <Component Id='ConfigComponent' Guid='266D3DA9-BBDD-44A9-B340-3AE28CF5EA0F'>
              <File Id='StansConfigFile' Name='ConfigFile.txt' DiskId='1'
        Source='..\WindowsService1\bin\Debug\Config\ConfigFile.txt' ReadOnly='no'   />
            </Component>
          </Directory>

Don’t forget to refer to this new component in the Feature section. And of course, the MajorUpgrade comes:

 <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit." />

This prevents us from installing older version over the latest Smile (if you don’t forget to place it in your older version!!)

3 comments:

Mihailo Lalevic said...

Hey Stan, this is brilliant, I was trying to do something similar some time ago, but with comparing WixPdb files. Had to scrap the effort since it wasn't deemed important. However with your post, I might try it again.

Anyway, slightly off the topic, I don't know how far you're through with WiX exploration, just thought to share a thing we're using here - variables. Put this under the Package:

<?define Source_Files_Folder = ..\WindowsService1\bin\Debug ?>

And then you can use your variable like this:
Source="$(var.Source_Files_Folder)\WindowsService1.exe"

Makes a difference if you have lots of files (I had 50+) and you can also pass variables from TFSBuild script, very handy.

Looking forward to your future WiX posts

stan said...

Thanks Mihailo! This is actually a very cool thing to know, will help a lot when I try to apply it in the real life soon.

stan said...

Actually I ended up using Robbins' paraffin for that http://www.wintellect.com/CS/blogs/jrobbins/archive/2007/10/21/wix-a-better-tallow-paraffin.aspx
Heat was quite unusable within the time I had for figuring out how to harvest.