I don’t write many installs these days, as most of my work is in SaaS-based web development. On occasion, however, there are some things that still must be done by installing something on-premise for a particular customer. In these rare cases, I’ll usually use WiX to create the install package. As I was writing such an install package recently, I ran across a problem that stumped me for a bit.
In this particular situation, I had written an Asp.Net Web API project that was hosted in a TopShelf-based Windows Service. Once installed on the customer’s local network, a web application would make JSONP calls (the customer was using older browsers) from the browser directly to the local service to collect data not stored in our SaaS platform. The installer needed to install the service, collect information about the account under which the service would run, and optionally allow the user to select the thumbprint of an X.509 certificate to run the service under SSL.
The flow of the steps in the installer wizard looked like the image below (click for a larger view).
In my main WXS file, my UI element was as follows…
What was interesting is that every time I would run the installer, the UI moved from ServiceUserDlg to VerifyReadyDlg, skipping the CertificateDlg regardless of whether or not I picked the option in the dialog to do so. I then ran the MSI from the command line using…
msiexec /i MyApplication.msi /l*v MyLogFile.txt
…and pored through the output log file. It indicated that the BASEPROTOCOL property that was controlling the dialog switching was set as expected.
Take a look at these lines from the WXS – specifically the “Order” attribute…
Now I make no such claim as to be a master of WiX, Windows Installer, or even the English language, but when I see the word “Order”, it generally implies that one thing follows another – a sequence if you will. The WiX documentation for the Order attribute reads…
This attribute should only need to be set if this element is nested under a UI element in order to control the order in which this publish event will be started. If this element is nested under a Control element, the default value will be one greater than any previous Publish element’s order (the first element’s default value is 1). If this element is nested under a UI element, the default value is always 1 (it does not get a default value based on any previous Publish elements).
Hmm. It seemed that Order did indeed have something to do with controlling the order in which the publish events are evaluated, but that it about all it told me. To make matters worse, I was so certain of my assumption that “Order” meant “sequence” that for a long time I never even considered the Order attribute as something that could be a problem. I kept thinking that the publish condition still wasn’t right, or something else was affecting it that wasn’t getting logged properly. As such, I searched quite a bit on Google for things like…
- WiX Publish element not firing
- WiX dialog out of order
- WiX next button wrong dialog
..none of which seemed to return anything helpful.
As it turns out, in Windows Installer Land, the word “Order” means something akin to “weight”. When multiple publish conditions are found that have the same “Dialog”, “Control”, and “Event” attributes, it will evaluate the conditions in order of largest to smallest Order, short-circuiting and using the first one that evaluates to true, and skipping the rest. I ended up finding this out by trial and error, eventually switching the numbers in the “Order” attributes, which made it behave correctly.
After finally figuring it out, I went back and did several Google searches specifically about Order being backwards, I eventually came upon this post, archived on Nabble from the WiX mailing list, where according to Blair Murri-3…
If you have more than one [BaseAddressDlg] event that has a true condition, the one with the highest order number will execute, and the others will be ignored. You need to make your conditions mutually exclusive.
So there we have it. In order to make one Publish element fire before another (when they both have the same “Dialog”, “Control”, and “Event” attributes), you must make its “Order” attribute larger than the others.
Since this took a while to figure out, I thought I’d post it. Hopefully this will help someone get to the answer faster than I did.