Automated Patch Building with WiX and Visual Studio
by bryanpjohnston
I’ve said previously that I generally prefer to implement major upgrades with each release and try not to worry about patching. I think it makes for a cleaner installation and is easier to manage. I mentioned in this post a way to update your installation by simply chaining an additional msi to your WiX bootstrapper. While that certainly is possible it feels a bit of a hack, and if you are fortunate enough to have authored your msi correctly from the beginning, you could use more traditional patch creation techniques. Until recently I haven’t had to create patches. While software companies are becoming more agile, there is a greater need to release software more often and deploy those updates online. I feel this creates a bigger need for patches. Furthermore, if you are developing a patch, you need an automated way of incorporating it into your build process so that it can be tested with each build. After working through this process recently, I thought I would share a method of automatically generating a patch with each build of your installer project.
For the purposes of this example, I will make the following assumptions:
- We have released version 1 of our installer called myProduct.msi
- The released version of myProduct.msi is stored internally on a server at the path //myServer/released/myProduct.msi
- The path to the WiX binaries is in our Path, so that we can run tools like Candle, Light, Torch, and Pyro on the command line without specifying the entire path to the executables.
Step 1: Create the Patch Authoring
Below is my Patch.wxs file which will specify which components I want to include in my patch. A few things to note.
- The PatchBaseline Id can be whatever you want to call it. You will just need to reference it later in Step4.
- You will add ComponentRefs to your PatchFamily if you want them to be included in your patch. Otherwise they will be ignored.
- You’ll see in my example below that I’ve included the PropertyRef for product version, so that the version information gets updated when I install the new patch.
<Wix xmlns=“http://schemas.microsoft.com/wix/2006/wi“ xmlns:util=“http://schemas.microsoft.com/wix/UtilExtension“>
<?include “..\Config.wxi”?>
<Patch AllowRemoval=“no“ Manufacturer=“$(var.Company)“ DisplayName=“$(var.InstallerProductName) Patch $(var.Build)“ Description=“Small Update Patch“ Classification=“Update“>
<Media Id=“5000“ Cabinet=“patch.cab“ EmbedCab=“yes“>
<PatchBaseline Id=“RTM“/>
</Media>
<PatchFamily Id=‘MyPatchFamily‘ Version=‘$(var.Major).$(var.Minor).$(var.Build)‘ Supersede=‘yes‘>
<PropertyRef Id=“ProductVersion“/>
<!–<ComponentRef Id=”MyComponent”/>–>
</PatchFamily>
</Patch>
</Wix>
Also, you will notice I use a lot of variables referenced in Config.wxi file. That file typically gets updated each build with the latest version number and new product codes, and will look something like this:
<Include>
<?define Company = “MyCompany” ?>
<?define Major = “1”?>
<?define Minor = “0”?>
<?define Build = “0”?>
<?define Revision = “0”?>
<?define InstallerVersion = “$(var.Major).$(var.Minor).$(var.Build)”?>
<?define InstallerProductName = “My Product Name”?>
<?define InstallerProductCode = “PUT-GUID-HERE”?>
<?define InstallerUpgradeCode = “PUT-GUID-HERE”?>
</Include>
Step 2: Perform Admin Installations of Your Released and Update Msis
In order to create a patch, we have to compare two msis to get their differences. We assume we already have the released msi sitting somewhere on a server. Therefore when we build the new version of our intaller, we can add PostBuild events (to the installer project itself) to copy our released msi to our temp directory, and perform administrative installations of each msi in the temp directory. This is necessary because in the next step we will use Torch to compare these two installations.
- Remove any previous installation from %TEMP%\MyProductInstall
- Copy the released version of the msi to your temp directory
- Perform admin install of released msi
- Perform admin install of recently built msi
FOR /D /R "%TEMP%\MyProductInstall" %%X IN (*.*) DO RD /S /Q "%%X" xcopy "//myServer/released/myProduct.msi" "%TEMP%\MyProductInstall\RELEASEDMSI\" /Y /I msiexec.exe /a "%TEMP%\MyProductInstall\RELEASEDMSI\myProduct.msi" /qb TARGETDIR="%TEMP%\MyProductInstall\RELEASEDMSI\Install" msiexec.exe /a "$(TargetDir)myProduct.msi" /qb TARGETDIR="%TEMP%\MyProductInstall\UPDATEMSI\Install"
Step 3: Generate the Differences Between the Msis
To generate the differences between the msis we will use the WiX tool Torch. In the example below, we compare the released msi with the update msi to generate the differences file diff.wixmst. Also, pay particular attention to the following command line switches:
- -a Indicates that these are administrative installs
- -xo Indicates the output file will be in wixout format rather than MST format.
We just add the following line to at the end of the PostBuild events for our installer project.
torch.exe -p -xo -a "%TEMP%\MyProductInstall\RELEASEDMSI\Install\myProduct.msi" -a "%TEMP%\MyProductInstall\UPDATEMSI\Install\myProduct.msi" -out "$(TargetDir)diff.wixmst"
Step 4: Building the Patch
Now we are ready to build the final patch. We use Candle and Light to compile and link our patch authoring from Step 1. Then we use Pyro to build the final Patch.msp.
- In my example, Patch.wxs is included in a “Patch” subdirectory in the solution, and not in the installer project itself. It’s up to you how you organize your solution.
- Notice the -t switch in Pyro. We pass it the PatchBaseline from Step 1 (in our case RTM), and the diff transform from the previous step.
Again the following commands can be added to the list of PostBuild events for your intaller project.
candle.exe "$(SolutionDir)Patch\Patch.wxs" light.exe "$(TargetDir)Patch.wixobj" -out "$(TargetDir)Patch.wixmsp" pyro.exe "$(TargetDir)Patch.wixmsp" -out "$(TargetDir)Patch.msp" -t RTM "$(TargetDir)diff.wixmst"
Step 5: Test
Once you add all the commands from Steps 2, 3 and 4 to your PostBuild events, your patch will get built each time you build your installer project. To install the patch, run
msiexec /p Patch.msp
or better yet, add it to the chain of your WiX bootstrapper.
Thanks for your post. I am also working on something similar and in our case we already have the steps to automate the first patch but now I want to automate the upcoming patches and the patches should be cumulative. It means that if a user has RTM and we have release 2 patches, then the client can get the Patch 2 and apply that straight rather then applying the patch 1 first. Currently I can manually change the WIX file and proj file to accommodate another successive patch but its just like copy pasting similar statements with different MSI locations. I am using PatchCreation property for creating the patches and I add the new Target property when we have new patch to release.
When patching, it’s usually better to (instead of only “msiexec /p Patch.msp”) use additional properties:
msiexec /p Patch.msp REINSTALL=ALL REINSTALLMODE=omus
the former way would make you end up after 1.0 + 1.2 + 1.1 with files from patch 1.2 being overwritten by files of version 1.1 (except versioned files…).
The latter will actually apply the patches in their correct sequence. so, even if you’d call 1.0 + 1.2 + 1.1, the msi installer would apply the 1.1 patch in it’s correct sequence like 1.0 + 1.1 + 1.2.
Again: for version files this might seem unsubstantial. But for non-versioned files, custom actions, etc. pp., this is mighty important.
pyro doesn’t seem to work in Visual Studio. Can you please tell me if you missed to mention any additional steps to get this working?
You want to make sure the path to the WiX Toolset binaries is set in your PATH, so when Visual Studio calls pyro, it recognizes it as a command.