Sometimes I wonder if Windows Installer will be the death of me. While I’ve successfully shipped device drivers, debuggers, and all sorts of bizarre products, I have to say that trying to get something installed on Windows is one of the more frustrating things I have encountered in my career. I can’t be the only one who feels getting files onto a machine in the approved manner is far more complicated than it needs to be. The horrible state of most installations we deal with speaks to that. If I were a high enough at Microsoft I would stop all development on Windows Installer 4.5 and make the team provide example installers for all the common scenarios as well as provide documentation that doesn’t assume you’re an install guru. Of course all the examples and documentation would be using Windows Installer XML (WiX) since Visual Studio “Rosario” is shipping WiX. Sorry for the venting, but sometimes you just have to. <g>
For a project I’m using WiX 2.0 on, I wanted to release a 1.00 .MSI file and have all the updates be patches. The big trick was that I wanted to have a single cumulative patch file. Thus, if 1.00 was installed on the machine, I wanted a patch file that would install a 1.01 patch. As we released additional patches, I wanted the patch file to be able to update a 1.00 installation no matter what previous patches were on the machine. In other words, if 1.00 is on the machine and 1.01 and 1.02 patches were applied, but the 1.03 patch was skipped, by applying the 1.04 patch, the final result would be that the machine would have the equivalent of a 1.04 straight install. It seemed so simple, but given the number of people asking the same question all over the web, I got a little worried that anyone less than an install ninja would be able to get it working.
The WiX patching tutorial shows you how to get started and show you how to build a patch that updates a 1.00 install to a 1.01 install. However, if you follow the instructions to build a 1.02 patch, you’ll find that creating the patch with the 1.02 build against the 1.00 build works, but if you have applied the 1.01 patch, the install fails with an installation 1642. If you create a patch against build 1.01 to build 1.02, you would have a patch that works. However, you can quickly see that’s going to descend into complete chaos from a patch management perspective. I don’t want to maintain twenty or thirty admin installs to build patches against each one. Also, I’d have to write a boot strap SETUP.EXE to look what patch level was installed in order to install the patches in the correct order.
Quite a bit of experimentation and web searching later, I found the tricks I needed. Heath Stewart mentioned the MinorUpdateTargetRTM property which “indicates that the patch targets the RTM version of the product or the most recent major upgrade patch.” That sounded exactly what I was looking for. Once I added the attribute to my PatchMetaData element, the 1.02 installer updated both 1.00 and patched 1.01 installs. Note that MinorUpdateTargetRTM is only supported with Installer 3.1.
Description=“Acme’s Foobar 1.0.2 Patch“
DisplayName=‘Foobar 1.0.2 Patch‘
With my patching working in a test case, I got to wondering how you would create a patch that would remove files. Fortunately, Trent Mick had the exact answer. If you need to remove a file, in the Component element for that file in the updated main .WXS file, specify RemoveFile for the file like the following:
Since I spent about six hours trying to figure all this out, I thought I’d share what worked for me.