AddThis Social Bookmark Button

Print

Introducing WiX

by Mike Gunderloy
04/19/2004

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.

A WiX Source File

So, what does a WiX source file look like? Well, here's a relatively simple one:


<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <Product Name="Fancy Hello" Id="4AA22F5D-D457-4A58-99FB-56AFF7FFD2CC" 
   Version="1.0.0" Manufacturer="Lark Group, Inc." Language="1033">
    <Package Id="6697CCC3-B351-4DCE-820E-DEAC87F57A2A" 
     Comments="This MSI file installs the FancyHello application" 
     Manufacturer="Lark Group, Inc." InstallerVersion="200" 
     Languages="1033" Compressed="yes"/>
    <Media Id="1" EmbedCab="yes" Cabinet="Fancy.cab"/>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder" Name="PFiles">
        <Directory Id="FHDir" Name="Fancy" LongName="FancyHello">
          <Component Id="SayHello Documentation" 
           Guid="8637E553-C046-60E0-9101-8D35A2870C86">
            <File Id="readme" Name="Readme.txt" 
             LongName="Readme.txt" DiskId="1" src="Readme.txt"/>
          </Component>
          <Component Id="Core" 
           Guid="B081FEDE-736F-541C-26EA-BA1015D31B37">
            <File Id="Main program" Name="FANCYH~1.EXE" 
             LongName="FancyHello.exe" DiskId="1"
             src="FancyHello.exe">
              <Shortcut Id="Program shortcut" 
               Directory="ProgramMenuFolder" Name="SayHello" 
               Target="DefaultFeature" Show="normal" 
               WorkingDirectory="TARGETDIR"/>
            </File>
          </Component>
        </Directory>
      </Directory>
      <Directory Id="ProgramMenuFolder" Name="PMFolder">
      </Directory>
    </Directory>
    <Feature Id="DefaultFeature" Level="1">
      <ComponentRef Id="SayHello Documentation"/>
      <ComponentRef Id="Core"/>
    </Feature>
  </Product>
</Wix>

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.


<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
...
</Wix>

After the standard XML header, every WiX source file must include the Wix root element, with a reference to the WiX schema.


<Product Name="Fancy Hello" Id="4AA22F5D-D457-4A58-99FB-56AFF7FFD2CC" 
  Version="1.0.0" Manufacturer="Lark Group, Inc." Language="1033">
  ...
</Product>

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.


<Package Id="6697CCC3-B351-4DCE-820E-DEAC87F57A2A" 
  Comments="This MSI file installs the FancyHello application" 
  Manufacturer="Lark Group, Inc." InstallerVersion="200" 
  Languages="1033" Compressed="yes"/>

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.


<Directory Id="TARGETDIR" Name="SourceDir">
  <Directory Id="ProgramFilesFolder" Name="PFiles">
    <Directory Id="FHDir" Name="Fancy" LongName="FancyHello">
      ...
    </Directory>
  </Directory>
  <Directory Id="ProgramMenuFolder" Name="PMFolder">
  </Directory>
</Directory>

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.


<Component Id="SayHello Documentation" 
  Guid="8637E553-C046-60E0-9101-8D35A2870C86">
  <File Id="readme" Name="Readme.txt" 
    LongName="Readme.txt" DiskId="1" src="Readme.txt"/>
</Component>
<Component Id="Core" 
  Guid="B081FEDE-736F-541C-26EA-BA1015D31B37">
  <File Id="Main program" Name="FANCYH~1.EXE" 
    LongName="FancyHello.exe" DiskId="1"
    src="FancyHello.exe">
    <Shortcut Id="Program shortcut" 
      Directory="ProgramMenuFolder" Name="SayHello" 
      Target="DefaultFeature" Show="normal" 
      WorkingDirectory="TARGETDIR"/>
  </File>
</Component>

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.


<Feature Id="DefaultFeature" Level="1">
  <ComponentRef Id="SayHello Documentation"/>
  <ComponentRef Id="Core"/>
</Feature>

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:


E:\Program Files\wix>candle fancyhellosetup.wxs
Microsoft (R) Windows Installer Xml Compiler version 2.0.1615.0
Copyright (C) Microsoft Corporation 2003. All rights reserved.

fancyhellosetup.wxs

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:


E:\Program Files\wix>light fancyhellosetup.wixobj 
Microsoft (R) Windows Installer Xml Linker version 2.0.1615.0 
Copyright (C) Microsoft Corporation 2003. All rights reserved.

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:


msiexec /x fancyhellosetup.msi 

Related Reading

XML in a Nutshell
A Desktop Quick Reference
By Elliotte Rusty Harold, W. Scott Means

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.


Return to ONDotnet.com