I’ve previously built installers using MakeMSI. It was fun. However, while submitting to an online store, the installer was rejected due to a problem with uninstallation. Since I have no idea what might be going wrong, and there isn’t much one can do to adjust uninstallation with MakeMSI, I decided to go another route, and I’ve decided to try out WiX – Windows Installer XML. In the process, I’ve learned much more about MSI than I wanted to know, and than I knew with MakeMSI (although that was already more than I wanted to know).
To upgrade an existing product, MSI installers use something called “upgrade codes”, versions and languages. MSI installers are databases plus CAB archives packed together. Table called “Upgrade” defines conditions under which a MSI will be upgraded: the minimum version, maximum version, language and action taken (plus some more attributes). This table is used by an action called “FindRelatedProducts“. Actions taken are specified in tables such as “InstallExecuteSequence” and “InstallUISequence”. These tables specify the “Action”, “Sequence” (smaller sequence means earlier execution) and the “Condition”. You can view all these tables using a tool called Orca.
That’s what MSI does. There is a reason I talked about this; please bear with me. However, we jsut want to get WiX to fill out the tables properly. This entire post is my understanding of something called a “major upgrade”.
First of all, each product has an ID and an upgrade code. A product contains a package which may or may not have its ID (I omitted it). You will want the product ID to be autogenerated – replace it with a *. If the product ID does not change, Windows Installer will complain with: “Another version of this product is already installed”.
Upgrade code must be unique per product, and must remain the same in future upgrades. This, along with the version (also specified in the product), is actually used to track multiple product versions. First three segments of a version are used by Windows Installer, so “188.8.131.52″ and “184.108.40.206″ are the same, but “220.127.116.11″ and “18.104.22.168″ are not the same to Windows Installer.
To generate “FindRelatedProducts” action, you need to add the following somewhere in your <Product>:
<MajorUpgrade DowngradeErrorMessage="A later version of this product is already installed. Setup will now exit."/>
So, having set the product ID to “*”, having set the upgrade code to what I used in MakeMSI, and having incremented version, the thing still does not work.
In cases like this, you will want to log the installation:
msiexec /lvx* log.txt /i game.msi
This specifies: “Hey, I’d like to log verbosely, extra debugging information, and all other log messages. Save this to log.txt. Run installation of game.msi.”
In there, I found this:
MSI (c) (10:20) [13:55:10:955]: Doing action: FindRelatedProducts MSI (c) (10:20) [13:55:10:955]: Note: 1: 2205 2: 3: ActionText Action 13:55:10: FindRelatedProducts. Searching for related applications Action start 13:55:10: FindRelatedProducts. MSI (c) (10:20) [13:55:10:959]: FindRelatedProducts: current install is per-user. Related install for product 'GUID HERE' is per-machine. Skipping... MSI (c) (10:20) [13:55:10:959]: FindRelatedProducts: current install is per-user. Related install for product 'GUID HERE' is per-machine. Skipping... Action ended 13:55:10: FindRelatedProducts. Return value 1.
As you can see, default installer built by WiX installs per-user, while default installer built by MakeMSI installs per-machine. A per-user installer will not upgrade a per-machine product.
We need to set the package’s install scope“:
<Package .... InstallScope="perMachine"/>
I’ll try to update this post with the finished .wix later on. Remind me if I forget to.
Note that above links might NOT be first parts of the articles.