Creating Windows Installers Using WIX: The Journey Begins
We all use them. Installers. They help get that sexy, shiny, new software safely onto our PCs and into our lives letting us frolic and play. Later, if things go sour or if the thrill is gone the installer is still there to reverse the process to help arbitrate the separation and keep what’s yours intact.
Recently I needed to make an installer for a web application product we have called Bolt. Dovetail’s own Gary Sherman created Bolt and it was good. It is a great too if you are a Clarify developer. Exciting things are in store for Clarify users regarding Bolt but I can’t steal that thunder. Creating the installer for Bolt made me realize I have a lot locked up in my head about deploying software. This is the first in a series of posts that are an attempt to do a brain dump to get this stuff off my chest and out there.
Windows Installer Tools
Tools for installers vary from the really simple and surprisingly powerful NSIS (exe) to pretty the easy to use yet difficult to maintain VS.Net deployment projects (msi) and on to the custom scripted and very expensive Install Shield (exe|msi) (it has been a long time since I used InstallShield it may have improved.) There are more tools out there and I hope people will chime in and school me about their favorites. If you are deploying to an enterprise environment your customer may be more comfortable using a technology that creates .msi installers which leverage the Windows Installer mechanism built into windows. Msi installers in the past have been either a pain to create or required an expensive tool to ease the pain. That is until Wix came along. Now MSI Windows Installers are cheap and … well less inconvenient to create.
The Windows Installer XML (WiX) is a toolset that builds Windows installation packages from XML source code. The toolset supports a command line environment that developers may integrate into their build processes to build MSI and MSM setup packages. (website – overview)
Wix was created by Rob Mensching and was one of Microsoft’s first open source projects released in 2004. Heck it is even hosted on Sourceforge.Net. Wix is used internally at Microsoft and by lots of open source projects and even has IDE support in VS.Net and SharpDevelop.
Why Wix?
I am going to be up front. Wix is not perfect.
- There is no WYSIWIG drag and drop developer crack to mainline.
- It is XML and it has a learning curve and you will have to crack open the documentation.
- It will take longer to figure out than NSIS.
That said what it does have makes it work for me.
- Wix generates MSI installers. Which is basically The Microsoft Way™ to do enterprise quality deployment.
- Wix gives me control. It is driven by XML so there is no IDE that gets in the way like VS.Net deployment projects do.
- You can easily integrate the creation of the installer into your automated build process.
- There is a community along with support from Microsoft that are improving Wix on a continual basis.
- Wix will replace VS.Net deployment projects in future versions of VS.Net.
I am surely not an expert at Wix. I have only created a handful of installers using it. My first one was the toughest and most complicated but things went smoother after I climbed up the curve. One of my goals with these posts will be to learn the toolset better and I look forward to hearing for you, dear reader, about your experiences, triumphs and trials with Wix and other windows installation tools.
Getting Started
Now that I am done defending why I waste my time using Wix, I’ll show you how to get a nice little toy installer building complete with build automation. In later posts I’ll go into more detail showing you how to make Wix jump through hoops. If you want a more comprehensive guide to creating Wix installers check out the Wix Tutorial.
The first thing to do is download the latest stable version of Wix. Grab the binaries and extract them to a tools directory under your project. I like to put all tools a project is dependant on in a tools folder committed to the trunk of project. Keep your source close and your dependencies closer (apologies Sun-tzu.)
Wix compiles XML into a windows installer .msi file. There are two main components that you work with the compiler candle.exe and the linker light.exe. There is a whole fire and paraffin motif going on here so pay attention.
My first .wxs file
I came up with a silly company called Pants Enterprises with a product called Pleats. Pleats is currently a very simple, and classic, web application only having one file. All that will happen when this installer is run is that default.asp will be copied to C:Program FilesPants EnterprisesPleats.
?xml version="1.0" encoding="windows-1252"? Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi" Product Name="Pants Enterprises Pleats" Id="{A263E591-B290-4db2-BF08-0C6FF24959A3}" Language="1033" Codepage="1252" Version="2.7.0" Manufacturer="Pants Enterprises Inc." Package Id="????????-????-????-????-????????????" Keywords="Pleats" Description="Pants Enterprises - Pleats" Comments="A web application for pants users." Languages="1033" Compressed="yes" SummaryCodepage="1252" / Media Id="1" Cabinet="Pleats.cab" EmbedCab="yes" DiskPrompt="CD-ROM #1" / Property Id="DiskPrompt" Value="Pants Enterprises - Pleats Installation [1]" / Directory Id="TARGETDIR" Name="SourceDir" Directory Id="ProgramFilesFolder" Name="PFiles" Directory Id="dirDovetailPrograms" Name="Dovetail" LongName="Pants Enterprises" Directory Id="INSTALLDIR" Name="Pleats" LongName="Pants Enterprises Pleats" Component Id="PleatsWebApplicationFiles" Guid="{9496E0F8-36AD-488f-9254-703A689D8D92}" DiskId="1" File Id="file1" Name="default.asp" src="$(env.pleats.dir)default.asp" / /Component /Directory /Directory /Directory /Directory Feature Id="Complete" Level="1" ComponentRef Id="PleatsWebApplicationFiles" / /Feature UIRef Id="WixUI_Minimal" / /Product /Wix
If you are following along and want to build the installer take the XML above and save it to a file in your project called:
.(project root)wixpleats.wsx
Let’s take a look at some of the pieces of this puzzle.
Product
The Product element represents the software being installed. Notice how the Product Id attribute has a GUID. You will want to make sure this is unique for your software. The first thing you do when creating a new installer is Generate a GUID to identify the product which will usually never change.
Components
Components are atomic units of installation. They are also identified by GUIDs and are usually groups of files that represent piece of the product being installed: executables with all their support assemblies, web applications with all their content files, documentation, sample applications. In the example above the component consists of a single File element but when we are done it will include file elements for all the files that compose the web application. Components can do more than define what files need to go where. They can create shortcuts, configure virtual directories on web servers, or even setup a windows service.
Feature
A Feature is the smallest installable unit. They are a collection of components that can be installed. This is for when you want to break your install into required and optional pieces. If you want to allow skipping including the documentation with the install, you can put the documentation files into a separate component and that component in it’s own feature.
UiRef
The UIRef element is referencing a chuck of standard installer that Wix comes with.
WixUI_Minimal features a simplistic user interface with a single dialog combining the welcome and license agreement pages. After that, the installation goes on automatically without allowing the user to customize anything. Use it when your application has no optional features to install. – Wix Tutorial : Section 2.3
If you want you can declare your own UI elements but it is a lot of work and it is much easier to use the standard user interfaces that Wix comes with. They are amazing time savers and have really simplified creating Wix installers. With this simple declaration you get an entire user interface for free. It is also pretty easy to do some basic customization of the look and flow of the Installer UI.
Note: If you didn’t pick this up already let me emphasize. The GUIDs in your installer should be your GUIDs. I just put some in there to make this work. Don’t copy these for your own application. Make your own.
Environment Variables
Notice the funny syntax in the File element:
File Id="file1" Name="default.asp" src="$(env.pleats.dir)default.asp" /
This is a Wix preprocessor declaration. It is not a good idea to put full paths in your .wxs your files. It couples you to an exact directory layout. In the build automation I will set an environment variable which will tell Wix what to replace $(env.pleats.dir) with.
Build Automation
You could go and run candle.exe and then light.exe with all the right inputs and switches. Or you could extract the NAnt (release .85) bin folder to your tools directory and use this handy automation I cooked up for you. The NAnt script below will copy the contents of the src directory (the web application) into a release folder and then invoke the Wix compiler and linker to create the installer. When this is all done there will be a pleats.msi file in the release directory.
xml version="1.0"? project name="pleats" default="build-release" xmlns="http://nant.sf.net/release/0.85/nant.xsd" target name="build-release" depends="clean, make-builddir, release-properties, copy-to-release, build-installer" / property name="tools.dir" value="${path::get-full-path('tools')}" / property name="src.dir" value="${path::get-full-path('src')}" / property name="build.dir" value="${path::get-full-path('build')}" / target name="clean" description="Delete automated build artifacts" delete dir="${build.dir}" if="${directory::exists(build.dir)}" failonerror="false"/ /target target name="make-builddir" description="Create build dir and build report dir" mkdir dir="${build.dir}" unless="${directory::exists(build.dir)}" / /target target name="release-properties" property name="release.dir" value="${path::combine(path::get-full-path(build.dir),'Release')}"/ property name="wix.dir" value="${tools.dir}wix"/ /target target name="copy-to-release" mkdir dir="${release.dir}" failonerror="false"/ copy todir="${release.dir}" fileset basedir="${src.dir}" include name="*" / /fileset /copy /target target name="build-installer" setenv name="pleats.dir" value="${release.dir}"/ delete fileset include name="${wix.dir}/*.wixobj"/ /fileset /delete exec program="${wix.dir}candle.exe" workingdir=".wix" commandline="pleats.wxs " / exec program="${wix.dir}light.exe" workingdir=".wix" commandline="pleats.wixobj ${wix.dir}wixui.wixlib -loc ${wix.dir}WixUI_en-us.wxl -out ${release.dir}pleats.msi"/ /target /project
Once you have NAnt’s binaries in your .toolsNant directory. Save the script above to a file called pleats.build in the project root. And invoke it using:
(project root).nanttoolsnant
If everything goes smooth the installer will be in your (project root)buildRelease directory. Double click on it and take it for a whirl.
What is next?
This is by no means a real installer. There is a bunch to do. I suppose I should finish up the installer for our web application. But that could take us into some more advanced topics who knows what I will get to. Here are what I see as the natural progression of this series.
- Generating Wix XML using Tallow – It is no fun making all those File and Directory tags by hand.
- Web Applications and Virtual Directories – How to create a virtual directory under IIS.
- Customizing The UI – Adding your own top and side banners to the standard UI.
- Adding a Custom Dialog – Add a custom dialog to one of the standard installer UIs.
- Launching An Application – It is pretty common to want to launch an application after the installation is complete.
- Invoking .Net Custom Actions – You may have some .Net code that you just have to run before the installation has completed.