In one of my installs, I have to install the base .MSI and an .MSP patch file. In the Windows Installer world, which exists to make your life as difficult as possible, that combination is a problem. While the user can double click on the .MSI to install it, double clicking on the .MSP won't apply the patch, because you must execute patches with the following command line:
msiexec /p MyPatch.msp REINSTALL=ALL REINSTALLMODE=omus
Yes, that's completely intuitive and something I'm sure every end user knows to do. Also, If your installer is more than one .MSI file, you've got a variation of the same problem. What you need is a bootstrap loader that handles the two (or more) steps to get your application installed. If you're using a commercial installation authoring tool, they come with bootstrap creators that handle these issues. In my case, I'm using the excellent (and free) WiX tool from Microsoft, which did not come with a bootstrap loader. There is a bootstrap loader creator as part of Visual Studio, and if all you need to do is install the .NET framework and run your .MSI, you're set. Sadly, it doesn't support patch files so I couldn't use it.
My initial attempt to solve my bootstrap loader problem was a batch file. My .CMD file first installed the .MSI followed by the .MSP. I did additional checking on the return values from MSIEXEC.EXE to report the exact failure. While not as sexy as a real bootstrap loader, it did get the job done. Unfortunately, I kept getting random bug reports that my installs were failing. I had my .MSI, .MSP, and the .CMD file packaged up in a .ZIP file for easy downloading. What turned out to be the problem was people were expanding the .ZIP file in Explorer's zip folders and double clicking on the .CMD file to run it from inside the .ZIP file. Turns out Windows is more than happy to run .CMD files from inside .ZIP files all day long. Of course, they run from the %TEMP% directory and don't unzip the rest of the file when running them. The bug was mine and so I needed to solve it.
As I had recently upgraded my installs to WiX 3.0, I was poking around the bin directory and noticed an interesting program: SETUPBLD.EXE. Running it, the help reported
Microsoft (R) Windows Installer Xml Self-Extracting Compiler version 3.0.5020.0
That sure looked fascinating to me so a quick search got me to a few links that mentioned it, but other than a few discussions of bugs and a few folks using it, that was all. Throwing my .MSI, .MSP and SETUP.EXE from the WiX bin directory into a temporary directory, I got to work playing with SETUPBLD.EXE to see if it could be my bootstrap loader.
Before I get into using SETUPBLD.EXE, I just have to say how impressive I find WiX. The project is something that was sorely needed and it has finally brought installation building to the development forefront. The folks developing it deserve a big round of applause. OK, back to SETUPBLD.EXE.
The first command line I tried was:
SETUPBLD -title "My Install" -m X.MSI -p X.MSP -s setup.exe -out test.exe
Running TEST.EXE, ran my installation followed by the patch, but it was in passive mode (where you just see the progress bars) so I didn't get to select features to install, but I was off to an excellent start.
Seeing that the –ms option, which shows the embedded MSI UI, I gave that a try:
SETUPBLD -title "My Install" -ms X.MSI -p X.MSP -s setup.exe -out test.exe
Running TEST.EXE again showed my MSI's UI as expected. When the MSI UI showed the last dialog, with the Finish button, clicking it showed the patch passive install progress bar. While I would have liked to have the patch applied before the user clicks the Finish button, I'm not complaining because in two minutes, I got a bootstrap loader!
That's all there was to it to make bootstrap loader with WiX 3.0 if you have to install an .MSI and an .MSP or multiple .MSI files. The output .EXE file is using the setup.exe stub from WiX so the next thing I wanted to do was to build my own version so I could have my custom icon and file detail information, like my product name and version numbers, in the .EXE. That meant grabbing the WiX 3.0 source code and pulling out the pieces needed to build SETUP.EXE. I don't know if I'm allowed redistribute the extracted source code so I'll err on the side of assuming I'm not (no need to talk to lawyers when you don't need to). Additionally, the development team has not pronounced WiX 3.0 as stable so if you do pull out the source code, you'll have to keep merging in any changes until it is declared stable to pick up bug fixes and new features. In other words, you are on your own if you follow the steps below.
These steps don't require C++ programming knowledge, but do assume you know how to set up C++ projects in Visual Studio
- Unzip the WiX 3.0 source code.
- Copy the .\inc, .\src\dutil, and .\src\setupexe directories to a different location. I found it easiest to put all three directories at the same level in the new location.
- Open .\setupexe\setupexe.vcproj
- Add the .\dutil\dutil.vcproj to the solution.
- In the setupexe.vcproj properties, add ..\inc, ..\dutil, and .\inc as additional include directories.
- In the setupexe.vcproj properties, set the Character set to "Not set" (the WiX code does not compile as UNICODE).
- In the setupexe.vcproj properties, set the Resources additional include directories to ..\inc.
- In the setupexe.vcproj properties set the Debug configuration to use the multithreaded debug (/MTd) runtime library. Set the release to use /MT.
- In the setupexe.vcproj properties, set the Manifest tool, Embed Manifest to NO (the .RC file already includes the manifest).
- In the setupexe.vcproj properties, set the linker additional dependencies to msi.lib comctl32.lib version.lib.
- In the solution properties, set the build dependencies so that setupexe is dependent on dutil.
The reason the .VCPROJ file does not build SETUPEXE is that the WiX team is using NANT to build instead of Visual Studio proper.
Once you have the SETUPEXE build working, you can start looking adding your icon to the .RC file and changing the file description information. Look in .\inc\wixver.h and .\inc\WiXDistribution.h for the values WiX had set so you can change them.
With WiX 3.0.5020, SETUPBLD.EXE does not support creating privileged EXE files that prompt for UAC elevation. If you need that for your installation to work, once you've configured the solution as I've shown, edit .\setupexe\setup.exe.manifest and change the level attribute to "highestAvailable."
Once I got my own custom setup exe building, I did some experimentation to see if I could create a bootstrap loader that would install just a .MSP file.
SETUPBLD -title "My Install" -pm X.MSP -s setup.exe -out test.exe
The –pm switch is the important one. If your base package isn't already installed, and you don't specify the –pm switch, the created bootstrap loader fails silently. With the –pm, you'll get the following error message. While still not super-descriptive, at least your end users won't be sitting there thinking the install worked.
While SETUPBLD.EXE won't solve all your bootstrap loader problems like downloading missing prerequisites, if you need to chain together a couple of .MSI files and .MSP files, it works great. The roadmap for the WiX 3.5 plans are all about BURN, which will be the ultimate "kick ass boostrapper." Until then, the WiX team has given us a little present which will handle much of what people need today.