Friday, November 3, 2006

Changing an install directory dynamically in WiX 2.0

Somehow this topic seems so common place and yet no where have I been able to find it spelled out clearly and simply. This reminds me of the joke about a helicopter pilot who's lost in the fog near Seattle, asks where he is and then is able to quickly navigate from there. When asked how he did that, he replied that the person in the window held up a sign saying "You're in a helicopter" which is such a typical engineer's response (accurate and truthful but not helpful or useful) so the pilot knew he was at the Microsoft campus and was able to navigate from there back to the airport.

If you need to set a directory "on the fly" either based upon a value from a dialog or some other means there are two things you need to do and one caveat:

  1. Create a custom action that sets the directory value:
    <CustomAction Id="AssignWebDir" Directory="WEBSITEDIR" Value="[WEBROOTDIR][SITE.NAME]"/>

  2. Schedule the action during the InstallExecution phase (must be after the CostFinalize step):
    <Custom Action="AssignWebDir" After="CostFinalize"><![CDATA[NOT Installed AND (&WebServer = 3) AND NOT (!WebServer = 3)]]/>

The caveat is that at the time you've scheduled the custom action the directory name, which is also a property, has been resolved. In the above example, assume that the parent directory, named WEBROOTDIR, is the default "C:\Inetpub\wwwroot\". Under the parent directory is where you've specified WEBSITEDIR to be. Even though you may specify an initial directory name (e.g. "mysite") on the <Directory> tag in the .wxs file you must use the full path when changing the name - thus the new value in #1 above contains the parent directory name and the site name (which I prompt the user for).

To round out the notes for the above example - the <![CDATA[...]]> syntax around the conditions "preserves" the xml integrity because of the ampersand (&) character in front of the Feature name. The full condition is if the product is not installed (i.e. it's being installed) and if the Feature (in this case the "WebServer" feature) is being installed locally and it's not already installed locally. Finally the Directory= attribute causes WiX to create a Type 35 Custom Action whereas using Property= causes WiX to create a Type 51 Custom Action. I mention that because they're briefly mentioned buried in the .chm help although not the online docs and not in the tutorial (more on that in a moment). When you're searching and trying things it's easy to miss that bit of info.

My "beef" and the reason for the reminder of the joke is that you can find lots of bits and pieces of WiX and MSI info such as "You can use a Custom Action to set a directory location" but the person giving the answer stops short of mentioning the rest or giving an example. I'm not picking on that one person - this seems to be the style and culture of the mailing lists on SourceForge. That is, I can find dozens of responses on directories and properties with Nabble (which does a much better job of indexing, searching and providing results of the SourceForge mailing lists) but nobody bothered to offer a concise and complete answer.

Even the WiX Tutorial which I'm sure took a lot of effort and a long time to compile and update mentions the "facts" in bits and pieces: 3.2 shows both examples of dynamically setting a directory using either a Directory= or a Property= attribute but fails to mention the difference (Type 35 or 51) or impact. I say both because you'll find both suggestions mentioned repeatedly on the mailing list without a complete example or a clear indication of which to use and why. The same 3.2 section shows how to schedule the actions up above the examples but doesn't mention that directories have to be scheduled after CostFinalize and require a fully-replaced path be specified because it's been resolved. It's only through more searching elsewhere on the mailing list that you can dig up the fact about cost finalize and scheduling directory/file name changes afterwards. Although nobody spelled out the little tidbit about paths already being resolved at that point. Also, 5.6 mentions creating directories (this is where you'd expect to find the information for changing them) but neglects to mention they can be changed and that to do so, you use a custom action with links back to the relevant 3.2 section showing that. Going beyond this, if you want to put together a dialog to prompt and pass values, you'll have to spend a lot of time in Lessons 2 and 8 as well as the mailing lists. ;)

Finally, Rob teased us with his last entry on the directory table and Type 51 actions here but at the rate he's been able to post it'll be around the holidays before we get the answer. ;)

I'll end my rant with one more Microsoft observation - I searched Rob's blog for "msi directory". What's the very first thing displayed at the top of the list? Why the number of results AND THE NUMBER OF FREAKIN' MILLISECONDS IT TOOK TO FIND THEM! Yeah, that's what I'm most interested in - NOT! Then there's the random order to the results list - not by date or title or even number of comments - who knows!

This is the tired helicopter pilot signing off from the fog around Seattle :)

Original post