*
Microsoft.com Home|Site Map
MSDN*
|Developer Centers|Library|Downloads|How to Buy|Subscribers|Worldwide
Search for


Advanced Search

MSDN Home MSDN Home
See this in the MSDN LibrarySee This in the MSDN Library

Using the WiX Toolset to Integrate Setup into Your Development Process

 

Rob Mensching
Microsoft Corporation

March 2005

Applies to:
   Windows Installer XML (WiX) toolset
   Visual Studio 2003

Summary: The Windows Installer XML (WiX) toolset enables developers to integrate setup development into their daily development process. This article describes why setup should be integrated and how to do so using the WiX toolset both in Visual Studio 2003 and from a custom build environment. (21 printed pages)

Download the sample code: WiXSampleCode.msi.

Contents

Introduction
Setup Development Is Just Development
What Is the WiX Toolset?
The Build Process Now with WiX
WiX Integration in Visual Studio
   Creating Your First WiX Project
   A First Look at the Default Product.wxs File
   Building the Product.wxs File
   Doing Something Useful with Product.wxs
Using the WiX Toolset Outside of Visual Studio
   The makefile to Build MyApp and MySetup
   Building with NMAKE Using Our makefile
Conclusion

Introduction

I spent my first few years at Microsoft working on the Office Setup Team. Creating the package to install, configure, uninstall, and repair a suite of applications as large as Office was always very exciting for me. So whenever I meet new developers, I like to ask them how they create their setup packages. Most of the time, they have no idea. But sometimes I meet the developer who finished his or her features first or the developer that was hired into the company last or, more rarely, the developer actually responsible for the setup package. Almost invariably I listen to a story about how the setup package was created at the last moment, under intense pressure to meet their ship date, no matter what the cost.

Sometimes, but not always, after finishing his or her story the developer will turn around and ask me how I create my setup packages.

This article is my story.

Setup Development Is Just Development

Traditionally the development process focuses on the creation of executables and libraries that make up an application. However, it is rare that those executables and libraries are all that is necessary for an application to operate correctly. Typically some registry keys, service registration, Web sites/virtual directories, and/or SQL scripts need to be installed on a machine before the application will operate correctly. All of those resources, including the executables and libraries, are tracked in your setup package. Therefore, I propose that your development process focus on the creation of the setup package for your application instead of the creation of the executables and libraries. That way when your development process is complete, you actually have an application you can ship to your customers.

Once you start considering the setup package as the output of your daily development process, you might ask, "Wait, if our setup package is a daily output, when do we have to start on writing setup?" The answer is simple. You start your setup development right after you have your build process working.

For example, let's say I decide to use Visual Studio to create my build process. The first thing I would create in my solution is the WiX Project (I'll discuss WiX Projects in Visual Studio more below). Then I would build, install, and uninstall my empty setup package before I add anything complicated. Now I know that if the project fails to build, install, or uninstall then the failure must be caused by a recent change because things worked at least once.

If you're reading between the lines of my previous paragraph, you might be wondering, "Is Rob seriously suggesting that each developer on the project should write setup?" I am and here is why. The developer who is adding code to the application is the person who knows what other resources are necessary for that code to execute properly. Why go through another developer to add resources to setup before the application can be expected to work? Let's take an example.

To create an out-of-process COM server requires a minimum of seven registry keys. Six of those registry keys require the correct GUIDs (there are two: the CLSID and the AppID) to be used. And that's for a COM server that doesn't implement any interfaces. To actually implement an interface requires additional registry keys and GUIDs. The developer creating the interface knows, or should know, what resources are necessary to communicate with his or her new COM server. Until those resources are properly configured the developer's code will not operate. Why shouldn't that developer be responsible for adding the resources to the setup package?

When I suggest each developer should be responsible for his or her setup code some developers suggest, "I don't have time to deal with setup coding. I have so much other stuff to do. Shouldn't setup be left to the setup experts?" I agree, it is a bit more work for each developer to create the setup code along with their other coding responsibilities. However, transferring the knowledge of what resources need to be included in setup is work that the developer needs to do anyway. I'm here today to show you how simple setup coding can be for the individual developer so that his or her effort goes directly towards shipping the final product instead of simply creating work for another developer on the team.

Finally, there will always be developers who specialize in solving the more intricate setup issues. This is no different than the fact that some developers specialize in network communication while others focus on UI programming. But area experts should be valuable references for solving difficult design issues or bugs, not bottlenecks that all coding for a particular area must go through.

I hope, if you're still reading, that you agree that setup development isn't different from other development work. But if you are still skeptical then I ask that you keep reading through the next couple sections where I start to describe how the WiX toolset allows you to treat setup development the same way you treat all of your other development tasks.

What Is the WiX Toolset?

The Windows Installer XML toolset is a collection of tools that convert source code into Windows Installer packages (MSI/MSM/PCP). Included in the toolset is a complete collection of build tools that you would expect for building source code. In particular there is:

  • A compiler and preprocessor called candle.exe that is responsible for converting source code into object files. As you might expect from the "XML" in "Windows Installer XML" the source code format for WiX is XML that follows the WiX schema, wix.xsd. We'll see what WiX source code looks like later in this article.
  • A linker called light.exe that is responsible for taking multiple object files plus all the other resources and creating the final setup package.
  • A library tool called lit.exe that can combine multiple object files into a library file. The library tool allows you to collect related object files into a library file to reduce the number of object files that you would otherwise have to track in your build process. Creating library files can be particularly useful when you have a very large number of object files (consider the size of Microsoft Office's setup). Since the examples I'll present here are very small, the library tool is not used in this article.
  • There is even a decompiler called dark.exe that converts existing MSI and MSM files into the XML source code form the compiler understands. Like the library tool, the decompiler is not used in this article.

These tools all operate from the command line so they are easy to integrate into your standard development process alongside your other tools. Also, very recently a Visual Studio 2003 add-in was added to the WiX toolset, so now you can build everything in the Visual Studio Development Environment. But before I demonstrate how to use the WiX toolset in the Visual Studio Development Environment and from a custom build environment, let's look at how the WiX toolset works with all the other tools in your typical build process.

The Build Process Now with WiX

As a developer, you are very familiar with the typical development process.

  1. You write the code.
  2. You build the code.
  3. You test and debug the code.
  4. You repeat steps 1 to 3 until finally you ship the code off to customers.

The majority of the WiX toolset integrates into the build process, so I want to focus there to continue demonstrating that setup development is just development. Figure 1 shows the inputs and flow of those inputs through the build process. Notice how the WiX toolset fits naturally into the flow.

 Click here for larger image

Figure 1. Typical build process with the WiX toolset in the middle (click image to enlarge)

Let's break down the levels in Figure 1 from top to bottom. At the very top of the process we have the developer who is going to write the code that will become the application we ship. Around the developer at the same level we have the external resources the developer needs to create the application. These external resources include libraries from the Platform SDK or assemblies from the .NET Framework that allow programs to show UI, write files to disk, read registry keys, and so on. Also included are the graphics, legal documents, or other content that needs to be distributed with the application.

At the second level of the flowchart, we have the source code that is created by the developer. Notice how the setup code sits right next to the managed and unmanaged code. I'll show how natural that position is in the next two sections.

At the next three levels we have the build process. In these levels the source code is compiled into an object file and then linked into the final result. Building managed code is slightly different because there is no link process but the result is the same. Notice how the link of setup objects takes the outputs from all of the other processes and creates the setup package. In that setup package should be everything you need to ship your final product.

I hope this flowchart shows that the setup package should be the focus of your development process. Writing the source code is important. Building the executables is important. But the setup package is what brings everything that goes into an application together and then configures the application on your customers' machines.

But I've teased you for long enough, let's go write some code.

WiX Integration in Visual Studio

Probably the easiest way to get started with the WiX toolset is to download the latest release of the WiX Visual Studio 2003 Add-in that we affectionately refer to as "Votive". The Votive.msi file contains everything you need to install the WiX tools, WiX documentation, and register with Visual Studio 2003 for IntelliSense and build tasks. Once you download the Votive.msi file, just double-click the file and Votive will install.

To verify that Votive was correctly installed, start your copy of Visual Studio 2003 and then click Help then About Microsoft Development Environment. You should see a dialog box that looks something like Figure 2.

Figure 2. WiX toolset registered in Visual Studio 2003 Help/About

Creating Your First WiX Project

As I mentioned in the beginning, the first project I create in Visual Studio is the setup project for my application. So, let's do that.

  1. Click File, then click New, then click Project.
  2. Choose the WiX Projects, then WiX Project, and name your project "MySetup" as depicted in Figure 3.

    Figure 3. Create a new WiX project

This should give us a new solution with the MySetup project and a Product.wxs file to get us started. Unfortunately, the Product.wxs file needs a bit more input before it will compile successfully. So let's take a moment to look at the Product.wxs file and discuss what needs to be done to get things building.

A First Look at the Default Product.wxs File

The Product.wxs file is our setup code. Everything we need to create our first setup package can live in this one file. So let's look at what Votive gave us.

Note   If you are not familiar with Windows Installer setup packages, I suggest reading though the MSDN documentation about the Installation Package before continuing. It will provide a lot of valuable context as we dig into the details of a Windows Installer setup package.
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <Product Id="PUT-GUID-HERE" Name="Your Product" Language="1033" 
Version="0.0.0.0" Manufacturer="Your Company">
    <Package Id="????????-????-????-????-????????????" 
Description="Description of your product" Comments="This will appear in 
the file summary stream." InstallerVersion="200" Compressed="yes" />

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

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLLOCATION" Name="MyAppDir" LongName="My Application Directory">

        <Component Id="ProductComponent" Guid="PUT-GUID-HERE">
          <!-- TODO: Insert your files, registry keys, and other resources here. -->
        </Component>

        </Directory>
      </Directory>
    </Directory>

    <Feature Id="ProductFeature" Title="Feature Title" Level="1">
      <ComponentRef Id="ProductComponent" />
    </Feature>
  </Product>
</Wix>

If you are familiar with the Windows Installer, the structure of the Product.wxs should be pretty recognizable. If not, that's okay because I'll provide links to all the relevant MSDN documentation.

First the Wix element exists purely to wrap the rest of the content in the file. The Wix element also specifies the namespace, the xmlns attribute that enables validation during compile and auto-complete in Visual Studio via IntelliSense. Next we have the Product element that defines the required Windows Installer properties used to identify the product, such as the ProductCode, ProductName, ProductLanguage, and ProductVersion. Third, the Package element contains the attributes for the Summary Information Stream that provides information about the setup package itself. The rest of the elements, except the ComponentRef element, map to Windows Installer tables by the same name, for example Media table, Directory table, Component table, and Feature table. The ComponentRef element is used to tie the Features to their Components and turns into entries in the FeatureComponents table.

Building the Product.wxs File

Now, you probably noticed I highlighted a couple attributes in the Product.wxs file above. Those are the attributes that we need to fix before the Product.wxs will build successfully. In fact, if you build your solution now you should see two errors (let's ignore any warnings for now):

C:\code\msdn\MySetup\Product.wxs(3):  The Product/@Id attribute's value, 
'PUT-GUID-HERE', is not a legal Guid value.  A Guid needs to be generated 
and put in place of 'PUT-GUID-HERE' in the source file.
C:\code\msdn\MySetup\Product.wxs(12):  The Component/@Guid attribute's 
value, 'PUT-GUID-HERE', is not a legal Guid value.  A Guid needs to be 
generated and put in place of 'PUT-GUID-HERE' in the source file.

The WiX toolset is telling us that we need to create a GUID for each of Product element's Id attribute and the Component elements Guid attribute. Votive provided us a template without GUIDs generated for us because it is important for us to keep track of which GUIDs we choose to use. You can read the MSDN documentation about component organization for more information about why it is important to track the GUIDs used in a setup package.

Before continuing, I want to point out the Package element's Id attribute. That attribute becomes the Package Code for our setup package. As the documentation about package codes notes, every nonidentical setup package must have a unique package code. Rather than force you to create a new GUID for the Package element's Id attribute each time you build your setup package, the WiX toolset provides a mechanism to automatically generate the GUID for you. As you can see in the example above, the syntax to instruct the WiX toolset to generate a GUID specifies question marks in place of all the hexadecimal characters. I should also note that this question mark GUID syntax can be used only for the Product and Package elements' Id attribute.

In any case, we need to create several GUIDs. There are many ways to create GUIDs, but I like to use uuidgen.exe because I'm a fan of the command line, plus Visual Studio ships with it. Look for uuidgen.exe in C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\tools\bin\.

Since we need two GUIDs, run "uuidgen.exe –n2" and you should see the following.

C:\Program Files\Microsoft Visual Studio .NET 
2003\Common7\Tools\Bin>uuidgen.exe -n2
ffffffff-ffff-ffff-ffff-ffffffffffff
eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee

Of course, you will get different GUIDs than I did, since GUIDs are supposed to be globally unique identifiers and, to be honest, I just faked mine. Anyway, now we can replace each "PUT-GUID-HERE" value with our newly created GUIDs and build successfully. Let's do that and you should see the build complete successfully in the Output window.

------ Build started: Project: MySetup, Configuration: Debug ------

Performing main compilation...
"C:\Program Files\Windows Installer XML\bin\candle.exe" -out bin\Debug\ Product.wxs

Microsoft (R) Windows Installer Xml Compiler version 2.0.2613.0
Copyright (C) Microsoft Corporation 2003. All rights reserved.

Product.wxs

Linking...
"C:\Program Files\Windows Installer XML\bin\light.exe" -out 
bin\Debug\Project.msi bin\Debug\Product.wixobj

Microsoft (R) Windows Installer Xml Linker version 2.0.2613.0
Copyright (C) Microsoft Corporation 2003. All rights reserved.

---------------------- Done ----------------------

    Build: 1 succeeded, 0 failed, 0 skipped

Your Product.msi will be placed in the bin\Debug directory under your project directory and should operate correctly. Go play with it. Install it. See it get registered in the Control Panel Add/Remove Programs. Uninstall it from Add/Remove Programs. See it disappear. Isn't this fun?

Doing Something Useful with Product.wxs

Okay, I'll be the first to admit that creating an empty setup package isn't terribly useful. However, it is good to know that our setup code works because we can successfully build, install, and uninstall our setup package. So let's do something useful and add an application to our solution. I'm going to create my application in C# (did you know most of the WiX toolset is written in C#?) but you can use whatever programming language you prefer.

  1. Click File, then select New, then select Project.
  2. Pick your Project Type and Template.
  3. Name your application "MyApp".
  4. Be sure to choose the radio button Add to Solution as depicted in Figure 4.

    Figure 4. Creating MyApp project in the solution

For the purposes of this article, I don't really care what the application does, so I'm not actually going to touch the application code. As it is, I can compile then launch my application to gaze at the glorious expanse of battleship gray that is my application's window before clicking on the X in the top right corner to shut the thing down. I hope your application will do something more exciting because I think I now have the market cornered for useless example applications.

But no matter what your application does, we need to get it to install via setup. So back to the MySetup project and our Product.wxs file to add this new application. While we are there, let's add a shortcut to our application to make it easier for others to enjoy the glorious expanse that is . . . yeah, okay, okay, back to work.

Open Product.wxs and you should see a comment that says:

<!-- TODO: Insert your files, registry keys, and other resources here. -->

Well, that's exactly what we're going to do. Delete that comment then add the following lines of code in its place:

<File Id="MyAppFile" Name="$(var.MyApp.TargetDosFileName)" 
src="$(var.MyApp.TargetPath)" DiskId="1">
</File>
Note   If you type that code into the editor (instead of copying and pasting from this article) you should notice that IntelliSense picks up the valid elements and attributes. IntelliSense with Votive and Visual Studio can save you significant amounts of typing and time when searching for the name of the elements or attributes as you become more comfortable with the WiX language.

That line of code instructs the WiX toolset to add a file resource to the setup package using "MyAppFile" as its package identifier. The Name attribute specifies the filename for your file when it is installed and the src attribute specifies where to find the file for packaging. Rather than hardcode values for these attributes into our source code, we use the WiX preprocessor variables that are passed to the WiX compiler by Votive. Here's a table of possible preprocessor variables provided by Votive.

Preprocessor Variable Example Variable Use Example Variable Value
var.<Project>.ConfigurationName $(var.MyApp.ConfigurationName) Debug|.NET
var.<Project>.ProjectDir $(var.MyApp.ProjectDir) C:\code\msdn\MyApp
var.<Project>.ProjectDosFileName $(var.MyApp.ProjectDosFileName) MYAPP.CSP
var.<Project>.ProjectExt $(var.MyApp.ProjectExt) .csproj
var.<Project>.ProjectFileName $(var.MyApp.ProjectFileName) MyApp.csproj
var.<Project>.ProjectName $(var.MyApp.ProjectName) MyApp
var.<Project>.ProjectPath $(var.MyApp.ProjectPath) C:\code\msdn\MyApp\MyApp.csproj
var.<Project>.TargetDir $(var.MyApp.TargetDir) C:\code\msdn\MyApp\obj\Debug
var.<Project>.TargetDosFileName $(var.MyApp.TargetDosFileName) MYAPP.EXE
var.<Project>.TargetExt $(var.MyApp.TargetExt) .exe
var.<Project>.TargetFileName $(var.MyApp.TargetFileName) MyApp.exe
var.<Project>.TargetName $(var.MyApp.TargetName) MyApp
var.<Project>.TargetPath $(var.MyApp.TargetPath) C:\code\msdn\MyApp\obj\Debug\MyApp.exe
var.SolutionDir $(var.SolutionDir) C:\code\msdn\MySetup
var.SolutionDosFileName $(var.SolutionDosFileName) MYSETUP.SLN
var.SolutionExt $(var.SolutionExt) .sln
var.SolutionFileName $(var.SolutionFileName) MySetup.sln
var.SolutionName $(var.SolutionName) MySetup
var.SolutionPath $(var.SolutionPath) C:\code\msdn\MySetup\MySetup.sln

Finally, the DiskId attribute instructs the WiX toolset to add this file to the Media element with matching Id attribute. In our case, this means that the MyApp executable is added to the "Product.cab" cabinet and that cabinet is embedded in the setup package.

Before you try to build your solution again, we need to make sure that the MyApp project is built before the MySetup project. If you remember our flowchart in Figure 1, the output from our managed and unmanaged code builds are inputs into our setup build.

To create the appropriate project dependencies, right-click on your solution and choose Project Dependencies . . . . In that dialog, choose MySetup for the Projects and check the MyApp box as seen in Figure 5.

Figure 5. MySetup project depends on MyApp project

I also promised that we would add a shortcut to the application, so let's quickly do that. Before I show you the code that we need to write to add a shortcut, can you guess where the code goes? If you guessed that our Shortcut element is going to be a child of the File element then you would be correct. Here is what our file plus shortcut code should look like:

<File Id="MyAppFile" Name="$(var.MyApp.TargetFileName)" 
src="$(var.MyApp.TargetPath)" DiskId="1">
  <Shortcut Id="MyAppShortcut" Name="MyAppSc" LongName="My Application 
Shortcut" Description="A glorious expanse of battleship gray!"  
Directory="ProgramMenuFolder"/>
</File>

Just like with the File element, the Shortcut element instructs the WiX toolset to create a shortcut resource in the setup package with "MyAppShortcut" as its identifier. On operating systems that only support short filenames, call the shortcut resource "MyAppSc" but on operating systems that support long filenames (Windows 95 and later) use "My Application Shortcut" instead. Also, the shortcut will be provided a glorious description. Finally, the shortcut will be installed in the Program menu folder, or Start, All Programs.

If you build now you will find that the WiX toolset complains about an unresolved reference to "Directory:ProgramMenuFolder". That error occurs because we said we want our shortcut installed in the Program menu folder but did not describe where to find the directory "ProgramMenuFolder" in our setup package. So let's add our definition for ProgramMenuFolder between our definitions of TARGETDIR and ProgramFilesFolder.

<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <Product Id="ffffffff-ffff-ffff-ffff-ffffffffffff" Name="Your Product" 
Language="1033" Version="0.0.0.0" Manufacturer="Your Company">
    <Package Id="????????-????-????-????-????????????" Description="Description of your product" Comments="This will appear in 
the file summary stream." InstallerVersion="200" Compressed="yes" />

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

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramMenuFolder"/>
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLLOCATION" Name="MyAppDir" LongName="My 
Application Directory">

        <Component Id="ProductComponent" Guid="eeeeeeee-eeee-eeee-eeee-
eeeeeeeeeeee">

There you go. You now have the beginnings of a setup package with great potential. It can install and uninstall your application. It even puts a shortcut on the current user's Program menu folder (although you may see complications when installing the application for multiple users, an exercise left for the interested reader). For those of you that think Votive and its integration of the WiX toolset into Visual Studio is the cat's meow, then feel free to skip down to the Conclusion of this article before heading back to your application project to start coding away. However, if you are interested in more detail about how to use the WiX toolset in your own build environment, read the next section of this article.

Using the WiX Toolset Outside of Visual Studio

As I mentioned above, I'm more of a command-line kinda' guy than an IDE kinda' guy. So, I thought it would be interesting to quickly demonstrate how to build the same example we created above without using Visual Studio. This section of the article will essentially go behind the scenes and show how the WiX toolset compiler and linker work together with the rest of your build process tools. I'm just going to copy the code from the example above and toss it all in a single directory. If you don't have the code from above, just pull it out of the sample code provided with this article.

If you're not at all interested in Votive and Visual Studio integration then you will probably be better off downloading the latest WiX binaries .zip file. In that .zip file you will find all of the tools, plus the WiX documentation. I suggest that you extract the .zip file into a directory on your PATH.

I'm going to use NMAKE to drive my build process in this example. NMAKE.EXE is included in Visual Studio 2003 and is also available for free in the Microsoft Visual C++ Toolkit 2003. While you're at it, if you don't have Visual Studio, then you'll want to grab the free .NET Framework SDK Version 1.1 download as well.

Now that we have all the tools necessary to create our own custom build process based on NMAKE, let's teach NMAKE to build MyApp and MySetup.

The makefile to Build MyApp and MySetup

For those of you that are new to NMAKE, NMAKE reads and executes the commands specified in a makefile. Makefiles specify targets and dependents. In extremely simple terms, targets are the things you want done and dependents are the things that must be done before you can execute the target's commands. The makefile to build MyApp and MySetup isn't very complicated, so let's look at it and see how the WiX toolset fits in.

###################
# makefile targets
#
full: clean Product.msi

clean:
  -del /q Form1.resources 2>nul
  -del /q MyApp.exe 2>nul
  -del /q Product.wixobj 2>nul
  -del /q Product.msi 2>nul

MySetup: Product.msi

MyApp: MyApp.exe

Product.msi: MyApp.exe Product.wixobj
  light.exe /nologo /out $@ Product.wixobj

MyApp.exe: AssemblyInfo.cs Form1.cs Form1.resources
  csc.exe /nologo /t:winexe /out:$@ /resource:Form1.resources 
AssemblyInfo.cs Form1.cs


###################
# makefile inference rules
#
.SUFFIXES: .resx .resources .wxs .wixobj

.resx.resources::
  resgen.exe /compile $<

.wxs.wixobj::
  candle.exe /nologo $<

At the top is the full target that has two dependents: clean and Product.msi. The full target has no commands itself, so it is essentially just another way to execute the clean and Product.msi targets in order.

The clean target is next and has no dependents. That means when the clean target is called, it executes only its commands, which in this case silently deletes all the files generated from a previous build.

Then we have the MySetup and MyApp targets. These targets are essentially just friendly names for the actual build targets Product.msi and MyApp.exe. I added these targets to our makefile to provide build targets analogous to what is provided by Visual Studio in the previous example. You might also note that the MySetup and MyApp targets are not referenced anywhere. That means these targets will only be used if explicitly provided on the command line to NMAKE.EXE.

The Product.msi target is actually the key target in the makefile. Here you can see that the Product.msi target is dependent on the MyApp.exe and the Product.wixobj targets. The MyApp.exe dependency ensures that our application is built before our setup package is linked by light.exe. If that dependency wasn't specified, then our setup package link process could fail if the application executable didn't already exist. The Product.wixobj dependency is more interesting.

The Product.wixobj dependency causes the inference rule at the bottom of the makefile to execute. The .wxs.wixobj inference rule takes all targets ending with ".wixobj" and compiles the file with the same name but with a ".wxs" extension instead using candle. Therefore, the Product.wixobj dependency causes our Product.wxs file to be compiled by the WiX toolset. You'll see the same thing happen for the managed code .resource files in the .resx.resource inference rule.

Now that we have the makefile done, let's go back and get our setup building with NMAKE.

Building with NMAKE Using Our makefile

Before we move on to building our application and setup package with NMAKE, let's take stock of what we have right now. We have all the tools downloaded and for convenience we placed the tools in directories that are listed on the PATH. We have also copied all the source code we wrote earlier in the Visual Studio example into the same directory that has our new makefile. I have the following files in my working directory.

Directory of C:\code\msdn\nmake

03/06/2005  12:31 PM    <DIR>          .
03/06/2005  12:31 PM    <DIR>          ..
03/05/2005  02:13 PM             1,078 App.ico
03/05/2005  02:13 PM             2,426 AssemblyInfo.cs
03/05/2005  02:13 PM             1,479 Form1.cs
01/29/2002  09:04 PM             1,733 Form1.resx
03/06/2005  12:11 PM               655 makefile
03/05/2005  04:09 PM             1,336 Product.wxs
               6 File(s)          8,707 bytes
               2 Dir(s)  23,370,448,896 bytes free

If you're missing any files, copy the appropriate ones out of the example package and we'll continue on with the building.

To build with NMAKE is as simple as typing "nmake" on the command line. This is true because by default NMAKE looks for a file named "makefile" and processes the first target in that file. In our case, we have a makefile and the first target is the full target. Therefore, running NMAKE by default will clean up any previously built files, which is unnecessary but harmless on our first time through, and then build our Product.msi. So let's see what happens.

C:\code\msdn\nmake>nmake
Microsoft (R) Program Maintenance Utility Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

        del /q Form1.resources 2>nul
        del /q MyApp.exe 2>nul
        del /q Product.wixobj 2>nul
        del /q Product.msi 2>nul
        resgen.exe /compile Form1.resx
Read in 0 resources from 'Form1.resx'
Writing resource file...  Done.
        csc.exe /nologo /t:winexe /out:MyApp.exe /resource:Form1.resources 
AssemblyInfo.cs Form1.cs
        candle.exe /nologo Product.wxs
Product.wxs
C:\code\msdn\nmake\Product.wxs(14) : fatal error CNDL0023: Undefined 
variable: $(var.MyApp.TargetDosFileName).
NMAKE : fatal error U1077: 'candle.exe' : return code '0x1'
Stop.

As you can see, the makefile first attempted to delete any previously built files. Those deletes silently failed but the makefile continued thanks to the "-" before the "del" command. Next the makefile processed the Form1.resx file and then compiled the managed code into our MyApp.exe application. Finally, the makefile executed the WiX toolset compiler and hit an error on line 14 that causes NMAKE to exit with a failure.

Hopefully this candle error is not surprising. Remember that when we wrote our File element we used a couple of preprocessor variables that Votive provides from Visual Studio. Don't remember? Well, here's my line 14 that is failing.

<File Id="MyAppFile" Name="$(var.MyApp.TargetDosFileName)" 
src="$(var.MyApp.TargetPath)" DiskId="1">

Notice the use of the two $(var.MyApp.Xxx) preprocessor variables. Those variables were provided by Votive. Since we're not using Votive any longer, we need to do something different. Fortunately, the changes are pretty easy.

<File Id="MyAppFile" Name="MyApp.exe" src="SourceDir\MyApp.exe" 
DiskId="1">

Now we are explicitly naming the file resource "MyApp.exe" during install and telling the WiX toolset it should find the binary named MyApp.exe in the root of the source directory for packaging. By default the source directory is the location where you execute light.exe. So in this example the source directory will be the directory where we execute NMAKE. Let's try the build again.

C:\code\msdn\nmake>nmake
Microsoft (R) Program Maintenance Utility Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

        del /q Form1.resources 2>nul
        del /q MyApp.exe 2>nul
        del /q Product.wixobj 2>nul
        del /q Product.msi 2>nul
        resgen.exe /compile Form1.resx
Read in 0 resources from 'Form1.resx'
Writing resource file...  Done.
        csc.exe /nologo /t:winexe /out:MyApp.exe /resource:Form1.resources 
AssemblyInfo.cs Form1.cs
        candle.exe /nologo Product.wxs
Product.wxs
        light.exe /nologo /out Product.msi Product.wixobj

Success! You should now have a Product.msi that is functionally identical to the Product.msi built in Visual Studio. Again, I encourage you to install and uninstall the setup package. Verify that the final output from your build process correctly configures your application and shortcut because when you're done testing you have everything you need to ship your application to customers.

Conclusion

We've now walked through two examples that focus on creating the setup package for our application. I want to reiterate how the WiX toolset seamlessly integrates into the build process in both Visual Studio and a custom build system. This article only scratches the surface of the WiX toolset's capabilities, but I hope it encourages you to consider that setup packaging is an integral part of your development process. Remember, writing setup code is the same as writing the other code that ships as part of your setup package.

I hope you've enjoyed reading my story as much as I've enjoyed writing it. If you are interested in learning more about the WiX toolset, I suggest that you read through the Help file (WiX.chm) provided with the WiX toolset and check out the Online WiX Tutorial. Until next time, keep coding. You know I am.

 


About the author

Rob Mensching has been working in the setup domain for over six years. He started as an intern on the Windows Installer team in 1998. He returned to Microsoft a year later where he spent three years working on the setup packages for Office XP and Office 2003. Rob is now a developer on the Windows Component Servicing team for Longhorn. Rob is also the project lead for the WiX toolset and blogs about his experiences in setup at http://blogs.msdn.com/robmen.

Rob would like to thank Justin Rockwood for Justin's spectacular efforts to release Votive as a part of the WiX toolset earlier this year. This article would have been half its size and half as valuable without Justin's efforts.

Top of Page Top of Page


© 2005 Microsoft Corporation. All rights reserved. Terms of Use |Trademarks |Privacy Statement
Microsoft