This article provides a simple guide about how to quickly create a WiX installer project for an existing WPF application or another Windows desktop application.
A real project which implements most of the described topics can be downloaded here.
First, install the WiX toolset from the following page:
The WiX toolset installer installs a new Visual Studio extension which provides some new project types. In this article, we will use the «Setup Project» project type.
After installing the WiX toolset, create a new installer project in your Visual Studio solution:
This chapter describes how to set up WiX so that all files from the application’s output directory get included in the installer MSI file. Automatic file harvesting is the simplest solution to generate the list of included files.
For the final installer which is used for production, you should think about creating this list manually because the automatically created list may include files which should not be included in the installer – for example .pdb files.
To enable automatic file harvesting, perform the following steps:
Target tag to add or update in the WiX project file:
SourcePath=MyOutputDirectoryPath
Replace the following placeholder with the correct value:
../MyApplication/bin/$(Configuration)).Remarks:
RunAsSeparateProcess to true so that a new process is started which exits after the harvesting. This ensures that no files are locked after harvesting the output directory.Next steps:
Target XML tag, close and save the project file and reload the project.Generated.wxs file is automatically updated.Generated.wxs. This file contains references to all files in the application’s output directory.Generated.wxs file and select «Include in Project».Remarks:
After generating the Generated.wxs we need to create the main installer file. To do so, create a new, empty WiX installer file called Product.wxs in the installer project and insert the following XML content:
The inserted XML has to be customized for your needs. Update the following placeholders:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX).Generated.wxs file in a tag like .AssemblyInfo.cs file in the application project and change the AssemblyVersion attribute to [assembly: AssemblyVersion("1.0.*")] so that each build generates a new assembly version. Additionally, by removing the AssemblyFileVersion attribute the file version is automatically set to the assembly version. This way you don’t have to manually increment the file version in your installer project and upgrades work hassle-free.Remarks:
Generated.wxs file do not change when the file is regenerated.Id attribute of the Product tag must be * so that a new package ID is generated each time the project is compiled. This is required so that each new MSI package has a new ID and the installer can detect whether a MSI package has changed.UpgradeCode attribute of the Product tag must not be changed for different MSI package builds. If the code has been changed, an older installation cannot be upgraded using the new MSI installer.EmbedCab attribute of the MediaTemplate tag specifies whether all data is embedded into a single MSI file, otherwise the MSI file also needs the .cab file.AllowSameVersionUpgrades to yes so that MSI packages where only the revision has changed are not treated as new products.After creating the Product tag, define a fragment which describes where the files should be copied to and what the installer should additionally do. Add the following XML after the Product tag in your Product.wxs file (replace the Fragment tags from the XML above):
Update the following placeholders:
Now, you can rebuild the project and a working MSI package should be created.
The next step shows how to create an application shortcut in the Windows Start menu. First, add an application icon to the Fragment tag so that it can be used in the WiX’s shortcut tag:
ApplicationIcon.ico.The «Icon» tag to insert:
Shortcut tag using the ID «ApplicationIcon».In the «Component» tag, add the following «Shortcut» tag:
Update the following placeholders:
Generated.wxs file (e.g. filBC52AFB6B1FDA82AFB5FC43E739D7309).When installing the generated MSI now, a new Start menu shortcut will be created.
The next step in this article is to register file extensions for the application. These registrations tell the Windows shell which application to open when double clicking on a document in the file explorer.
First, you have to add a new file icon (e.g. FileIcon.ico) to the application project and change the file properties the same way as for the icon in the previous chapter. Then rebuild the installer project so that the new icon gets included in the Generated.wxs file. To enable the registration of a new file association, simply insert the following XML tag into the Component tag in the Product.wxs file:
Update the following placeholders:
filBC52AFB6B1FDA82AFB5FC43E739D7309)Generated.wxs file (e.g. filBB90AF377506520F6D8B60A0568383B4)To handle file open – triggered for example when double-clicking a file in Windows explorer – simply run the following C# code when the application has been started (e.g. in the main window’s «Loaded» event):
var args = Environment.GetCommandLineArgs();
if (args.Length > 1)
{
var fileName = args[1];
if (File.Exists(fileName))
{
var extension = Path.GetExtension(fileName);
if (extension == ".MyDocumentExtension")
{
// TODO: Open file from fileName
}
}
}
To simplify this, use the classes mentioned in the next chapter.
By default, every time a file is opened by double-clicking in the Windows explorer, a new application instance is started – the file is not opened in the existing application process. There is no trivial solution to this problem.
One possible solution is to have your application create a named pipe. On application start, check for the existence of this named pipe. If the pipe exists, open it and use it to send the filename being opened to the already existing application instance, and then terminate the second application instance. If the named pipe does not exist, no other instance of the application is already running and the application opens the file itself.
The FileOpenHandler class from the MyToolkit library helps you implement this mechanism as well as reading the command line arguments described in the previous chapter.
To use this class, simply add the following code in the constructor of your main window:
var fileHandler = new FileOpenHandler();
fileHandler.FileOpen += OnOpenFile;
fileHandler.Initialize(this);
Now, the OnOpenFile method is called whenever a file should be opened:
public void OnOpenFile(object sender, FileOpenEventArgs args)
{
// TODO: Open file from args.FileName
}
You can download the classes here:
As you can see, creating a WiX installer project and setting it up does not take that much time. Having a build step which automatically generates a MSI installer provides a big benefit for testing and deploying the newest application version to end-users. Of course, you can do much more then explained in this short article – for example implement a custom installer GUI.
The following list provides some links for further reading:
What is the reason that «The file IDs in the Generated.wxs file do not change when the file is regenerated»?
I tested it by adding/deleting files from the directory, and indeed! the file id did not change. how does that work?
Nice Idee with automatic Version-update with AssemblyVersion atribute.
But sorry i don´t get running your example.
Do you have a complete running example for me?
Im stuck with the replace MyApplicationExecutableId – I get an error that my fileid (copied from generated) is wrong. It would be great with a full example