Simulating VS.net’s MSI InstallURL property with WiX
Posted by Michael Bray on October 24, 2009
I recently converted several installers from VS.net to WiX. In one of those installers, I was using a Registry Search condition to check to see if MSXML6 was installed, since the application requires it. If it wasn’t installed, I was using Visual Studio’s InstallURL property to redirect the user to the Microsoft download page for the package so they could download and install it.
WiX doesn’t appear to have an InstallURL property available by default, but you can simulate it with some custom actions. Along the way I learned quite a bit about how WiX structures CustomActions, and experienced quite a bit of frustration getting it to work. The first step to simulating the InstallURL capability is to set up a Property that searches the registry for the MSXML key:
<Property Id="MSXML6"> <RegistrySearch Id="MSXML6Search" Root="HKCR" Key="Msxml2.DOMDocument.6.0" Type="raw" / </Property>
This code is very standard code for polling a registry value – no surprises here. The next step is to build in two custom actions that both tie to this property:
<Property Id="cmd" Value="cmd.exe" /> <CustomAction Id="OpenMSXML6Download" Property="cmd" ExeCommand="/c start http://www.microsoft.com/downloads/details.aspx?FamilyID=993c0bcf-3bcf-4009-be21-27e85e1857b1" Execute="oncePerProcess" Return="check" /> <CustomAction Id="OpenMSXML6DownloadError" Error="MSXML6 must be installed first." />
The first Custom Action executes a command window, and starts the URL in the ExeCommand. The important and confusing thing to note here is that the actual command to execute is put in a property, and any parameters are put in “ExeCommand” which is very poorly named. The parameters in this case are a trick to start up the default browser to the desired URL. The minor drawback to this is that you see the command window briefly. I think there is a better way to do this that I’ve seen but not yet tried that involves doing a registry search to locate the default browser executable and then calling it directly.
The second custom action simply opens an Error dialog and exits the installation.
The third piece to this puzzle is to insert the Custom Action into the InstallExecuteSequence:
<InstallExecuteSequence> <!-- Takes user to MSXML6 download page to be installed --> <Custom Action="OpenMSXML6Download" After="AppSearch">NOT MSXML6 AND Not Installed</Custom> <Custom Action="OpenMSXML6DownloadError" After="OpenMSXML6Download">NOT MSXML6 AND Not Installed</Custom> </InstallExecuteSequence>
One critical piece of information here is to note the “After=AppSearch”. When I was first trying to get this to work, I dealt with an huge amount of frustration because I had set this to “After=FindRelatedProducts”. I had chosen this because although I don’t show it above, this particular WiX install also enables the app to install over itself and prevents downgrading, and in that scenario, that’s the After value that you use. My assumption that it would work to simulate the InstallURL was a very bad one. The problem is that FindRelatedProducts occurs before AppSearch, which is where the RegistrySearch property is evaluated. As a result, the MSXML6 property was NEVER defined and I was redirecting to the download page even if MSXML6 was installed. (BTW this is a good reason to download and install the Windows SDK tools – I only discovered this because I bothered to open the MSI in Orca!)
With these three pieces in place, the installer now correctly detects MSXML6 and will redirect the user to the download page (and terminate) if it isn’t installed. Note, however, that as presented above, the user may have to go thru the majority of the UI install before this happens. If you don’t want the user to see any of the UI before the check and redirect takes place, duplicate the InstallExecuteSequence lines into the InstallUISequence section of the WXS file. I’ve been told it’s somewhat of a bad practice, but that does fall more in line with the way the Visual Studio InstallURL works.