WiX Publish Element Skipped if Multiple Next Steps Exist (or Burnin’ the WiX at Both Ends)


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…

<UI Id="IntegrationFrameworkUI">
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="ServiceUserDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
<Publish Dialog="ServiceUserDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish>
<Publish Dialog="ServiceUserDlg" Control="Next" Event="NewDialog" Value="BaseAddressDlg">NOT Installed</Publish>
<Publish Dialog="BaseAddressDlg" Control="Back" Event="NewDialog" Value="ServiceUserDlg">NOT Installed</Publish>
<Publish Dialog="BaseAddressDlg" Control="Next" Event="NewDialog" Value="CertificateDlg" Order="1"><![CDATA[(NOT Installed) AND (BASEPROTOCOL = "https")]]></Publish>
<Publish Dialog="BaseAddressDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="2">NOT Installed</Publish>
<Publish Dialog="CertificateDlg" Control="Back" Event="NewDialog" Value="BaseAddressDlg">NOT Installed</Publish>
<Publish Dialog="CertificateDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">NOT Installed</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="BaseAddressDlg" Order="1">NOT Installed</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>

view raw


hosted with ❤ by GitHub

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…

<Publish Dialog="BaseAddressDlg" Control="Next" Event="NewDialog" Value="CertificateDlg" Order="1"><![CDATA[(NOT Installed) AND (BASEPROTOCOL = "https")]]></Publish>
<Publish Dialog="BaseAddressDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="2">NOT Installed</Publish>

view raw


hosted with ❤ by GitHub

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.

<Publish Dialog="BaseAddressDlg" Control="Next" Event="NewDialog" Value="CertificateDlg" Order="2"><![CDATA[(NOT Installed) AND (BASEPROTOCOL = "https")]]></Publish>
<Publish Dialog="BaseAddressDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="1">NOT Installed</Publish>

view raw


hosted with ❤ by GitHub

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.

Tagged ,

8 thoughts on “WiX Publish Element Skipped if Multiple Next Steps Exist (or Burnin’ the WiX at Both Ends)

  1. Kyle says:

    Thank for your posting. Now mystery solved!!!

  2. dan says:

    Thank you…… Solved after hours!!

  3. Tobias says:

    Thank you for clarifying this counterintuitive term “order”. At first glance, it seems you do not need this attribute for dialogs because you could keep your conditions mutually exclusive (as Blair Murri-3 suggests). However, when you want to overwrite default behavior (e.g., moving to a custom dialog instead of SetupTypeDlg when the user presses the “Next” button in LicenseAgreementDlg), then you cannot change the condition of the default event. Of course you could rewrite the required default dialogs. But giving your custom event a higher order is a much simpler and cleaner solution.

  4. Willy says:

    Thanks for this!

  5. Same comment … Thank you! … Solved after hours of struggle!!

  6. RR says:

    Awesome!!! That fixed my issue too!! Thank you so much for posting this!

  7. Dave says:

    Thanks! That fixed my issue!

  8. Johnny says:

    Wtf honestly. I spent so many hours figuring this out. I wasn’t even looking at order property, assuming it’s self explanatory. I was looking at everything else. Even told my boss that something is fucky.
    This was my last google search result before I’d turned in suboptional solution.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: