Another WiX post! I have a feeling there will be several of these, because it's the source of much ... learning for me lately.
One of the more convenient aspects of the old Visual Studio Installer projects was the ability to easily set a required version of the .NET Framework and have it magically installed along with your application. With other installer tools, that's a bit more difficult, but not by much.
This problem is as old as the .NET Framework, though these days it's less of a hassle; I remember back when the .NET Framework being a 20-meg download was a big deal1. Nowadays most machines already have it installed, but in my case I needed to support .NET Framework 4 Client Profile on a completely vanilla install of Windows 7. Which means I needed my installer to run the .NET installer. This requires building a 'bundle', which in WiX is basically a lightweight executable which calls multiple installers in sequence. The .NET installation scenario is a common case, so there's already some documentation for it. Like most documentation for this sort of thing, it's ... not expansive. So I'll tell you what I did to get this working, in the hopes that it will help someone.
I already had a working working installer project which would build an
.msi file for the primary application; that project is named 'Product.Installer'. I created a second project (using the 'Bootstrapper' template the the WiX toolset adds to Visual Studio) called 'Product.Bootstrapper'.2 At that point I've got a new Bootstrapper project with a file called
The next step was to add references to both the 'Product.Installer' project and the actual 'Product' project. Then, since we're looking to check for (and possibly install) the .NET Framework, we need a reference to
WixNetFxExtension, which can be found in the WiX toolset's
Now we can actually set up the installer chain in
Bundle.wxs. It should look something like this:
<Wix ... xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"> <Bundle ...> ... <Chain> <PackageGroupRef Id="NetFx40ClientWeb"/> <MsiPackage Id="Product.Setup" SourceFile="..\Product.Setup\bin\$(var.Product.Configuration)\Product.Setup.msi" /> </Chain> </Bundle> </Wix>
The first part of the chain is running the web setup for the .NET Framework 4 Client Profile. It's actually referencing a package that's defined in the
WixNetFxExtension we referenced earlier - that's why we need to reference that namespace in the
Wix element. I'm using the web installer instead of a redistributable installer; all the combinations of framework version and web/redist are available as package groups. If the user already has this version of the framework installed, this won't do anything.
WiX provides a mechanism for detecting if a sufficient version of the framework is installed (for example, if the user already has the full 4.0 Framework installed, they don't need to also install the Client Profile to run my application); I've ignored that for the time being because this solution was sufficient and I had other things to focus on. Eventually I'll come back to this and make the installer more elegant.
The second part of the chain is my application installer. The
MsiPackage element is pretty straightforward. Note that the default when you're using a bootstrapper to launch the
.msi is to suppress any UI in the
.msi; you'll see the bootstrapper's UI instead. You can override this, but I wouldn't usually recommend it. By letting the bootstrapper run all the other installs in the background, you get a unified UI for the entire installation process. If you required user interaction in your installer (e.g., customizing the installation folder or accepting a license agreement), you can customize the bootstrapper UI to handle that stuff and pass the results on to your
We can't bust heads like we used to, but we have our ways. One trick is to tell 'em stories that don't go anywhere - like the time I caught the ferry over to Shelbyville. I needed a new heel for my shoe, so, I decided to go to Morganville, which is what they called Shelbyville in those days. So I tied an onion to my belt, which was the style at the time. Now, to take the ferry cost a nickel, and in those days, nickels had pictures of bumblebees on 'em. Give me five bees for a quarter, you'd say. Now where were we? Oh yeah: the important thing was I had an onion on my belt, which was the style at the time. They didn't have white onions because of the war. The only thing you could get was those big yellow ones... ↩
By this point the solution starts to get cluttered, so I actually put all the installer-related stuff in it's own solution folder. That makes things look a lot cleaner in VS. ↩