Introducing WiX

Microsoft recently surprised quite a few people by releasing an application
under an open source license (the Common Public License, to be precise) and
hosting its source code on SourceForge, the premier open source community site.
Though this isn't the first time Microsoft has shipped open source code (take
a look at Services for Unix some time), the politics of the Windows
Installer XML (WiX) project were heavily discussed in the wake of this release.
But what about the technical aspects? It turns out that there's a lot of yummy
goodness here for the developer who wants to integrate setup building into the
development process, using an easily controlled XML file format. So in this
article, I'm going to sidestep the politics and concentrate on what you can actually
do with this stuff.

Some Basic Concepts

To start with the obvious, WiX is a set of tools for taking XML files
(structured according to a particular schema) and turning them into MSI files.
MSI files, of course, are the source files used by the Windows Installer Service
to install new software. Using the Windows Installer Service for this purpose
offers all sorts of benefits, from Add/Remove Software support to automatic
nondestructive rollback if there's any problem with the installation.

At big companies like Microsoft, the people who write setup programs do
nothing but write setup programs. For most of us, though, writing the setup is a
sideline to the rest of our development efforts. Before you get started with a
Windows Installer tool, there are a few basic concepts that you need to
understand. Here are four of the key ones:

A product is some chunk of software that you're installing. A product
might be as large as Microsoft Office 2003 Enterprise in Japanese, or as small
as a "Hello World" application including a single file. Each product is
identified by a GUID, the product code. You aren't required to change the
product code if you make a "relatively minor" change to the files for a
product.

A package contains everything that the Windows Installer Service
needs to install a particular product. This includes the appropriate MSI files
and any external files (such as CAB files) that the setup needs. Packages, too,
are identified by GUIDs (known as package codes). If you make any change to a
package, you must assign a new package code.

A feature is a piece of functionality that makes sense to the end
user of the software. The help system could be a feature, or spell-checking, or
wizards. If you've ever installed software that displays a treeview of things
that you can choose to install or leave out, those are individual features.
Features are identified by strings that must be unique within a particular
package.

A component is a unit of software that the Installer can install.
Components can include files, registry keys, shortcuts, resources, and other
things. Each component is identified by a GUID, the component ID, which must be
unique across all packages, regardless of product.

These four concepts just scratch the surface of the complexity of the
Windows Installer Service, but they're enough to get you started with WiX. If
you get deeply into the subject, you'll want to pick up a reference to the
database used by the Installer. The independent InstallSite web site has a good
list of books on the subject, or you can
find the Windows Installer documentation in the MSDN Library.

Building Installer Files

The Windows
Installer SDK includes some command-line tools and a very basic editor named
Orca. With these tools, you can build a package that makes use of all of the
functions of the Windows Installer Service. So why look any further? Well, the
tools, though comprehensive, are not especially powerful or easy to use.

Fortunately, the SDK does not stand alone. A number of companies, such as Wise and InstallShield, have built tools that help
build Installer packages. These tools help the novice or experienced author
wring the most out of the Installer Service, and usually include user interface
editors, ways to automatically pick up dependencies, wizards, and other powerful
tools. Even Microsoft has gotten into the act; the setup projects in Visual
Studio .NET are also, under the hood, just building Installer packages.

But these developer-oriented tools are not generally a good fit for an
automated build process, especially one that may be called upon to determine
which software to include in a setup based on other factors (such as recent
check-ins, changed filenames, and so on). That's where WiX comes in. The WiX
tools allow you to define the structure of a Windows Installer package using an
XML file. This gives you all of the usual benefits of XML: easy editing with a
variety of tools, the ability to modify the files using well-known technologies,
and the ability to put the source file under source code control, for example.
The WiX tools themselves are command-line tools, so they fit well with almost
any build process.

This file, when properly built with the WiX tools (I'll show you how to do
that in a little bit) will install a slightly souped-up "Hello World"
application consisting of a single executable file and a readme file, and it
will add a shortcut to the Start->Programs menu to run the application. Before I
show you how to build it, let me go through the file, piece by piece, to discuss
what's in it.

As you can no doubt guess, the Product element defines the product that the
Installer will install. This is the first case where you can see a common WiX
pattern: the name of the element corresponds to a table in the Windows Installer
database, and the attributes correspond to the columns in the table. However,
the correspondence is not exact. For instance, the Installer database includes
foreign key columns to relate many tables, while the WiX source files use
nesting to accomplish the same relation. The WiX tools take care of defining the
appropriate foreign key values for you.

Within the Product element, you'll find a single Package element, defining the package that corresponds to this WiX file.

<Media Id="1" EmbedCab="yes" Cabinet="Fancy.cab"/>

The Media element defines the distribution media where the MSI file and any
associated CAB files will be stored. In this particular case, I set the EmbedCab
attribute to yes to embed the CAB file in the MSI file, so the final package
will consist of a single file. You can define more than one Media element for a
single package; this was more important back when we used to ship software
spread across multiple diskettes.

The Directory elements define the hierarchy of directories that the Installer
Service will use with this software. Note that the Id attributes are not
completely arbitrary. The Windows Installer defines a number of special
directories, including the two (the program files folder and the program menu folder)
that I'm using in this example.

The Component elements and their child elements define the exact software
that will be installed. In this case, the first component consists of a single
file, while the second includes a file and a shortcut to the file. Note that WiX
will look for the files that you include relative to the XML file. The best
plan is probably to place the XML file in the same folder as your source files,
and place the WiX tools on your path.

Finally (in this case), the Feature element defines both the single feature in
this package and the mapping between features and components; in this case, the
feature includes both components.

MSI files can, of course, perform extremely complex tasks, and the
corresponding WiX source files are much more complex than this one. You'll want
to have both the Windows Installer SDK and the WiX documentation handy as you
develop more complex files.

Building and Testing

Turning a WiX source file (which has the extension .wxs, by convention) into an
MSI file is a two-step process, with both steps being carried out by command-line tools. The first of these tools is the compiler candle. Here's a candle
session:

Unless something goes wrong, the output from the WiX tools is very terse;
candle just echoes back the name of its input file. You can even use the -nologo
switch to suppress printing the copyright information, if you like. Terse
utilities are better for command-line automation, so this is a nice feature. The
next step is to use light, the linker:

Assuming that light didn't find any errors, you've now got an MSI file ready
to go. Though you could launch the setup by double-clicking it in Explorer, it's
worth knowing that there's a Windows Installer tool to kick it off from the
command line:

msiexec /i fancyhellosetup.msi

And when you're done testing, you can uninstall with the same utility:

Note that the uninstall switch is /x, rather than the /u that you might be
expecting.

Finally, there's one more WiX tool that you should know about: dark. dark
takes an existing MSI file and produces the corresponding WXS file. This is a
good way to learn how the pieces of a WiX source file fit together. But beware:
WiX source files can get very large for complex installations.

What Next?

I could go into detail on many more aspects of building MSI files with
WiX, but that would take an entire book to complete. Instead, let's pull
back for a moment and think about the big picture. Given this toolset, the
process of building an Installer package comes down to properly crafting the
original XML source file. You can imagine this source file being kept under
source code control, so that changes can be tracked (and quickly rolled back
in case of disaster). You can also see how it could be (in part or completely)
automatically generated. A complex software product might have an inventory
of hundreds of features and components that it needs to install. Given the
ability of Access or Excel to export to XML these days, it would make sense
to maintain that inventory in a database or spreadsheet, and automatically
build the relevant part of the WiX source file. Ultimately, a setup file
could be created by many different developers, each working out their own
part of the XML source file using automated tools.

Can this sort of scheme work? Absolutely! I can be confident in making that
statement, because WiX is part of Microsoft's well-known dog food. This tool has
been used by many teams inside of Microsoft for years now, and it's stood the
test of time. With its release as open source, you have the added security of
being able to dig in and add new features if you really need to. WiX is
definitely a win-win situation for setup authors, and I expect to be digging
into it in more depth the next time that I need to put together an Installer
package.

Mike Gunderloy
is the lead developer for Larkware and author of numerous books and articles on programming topics.