In this blog post I'm going to describe how you can use a Setup and Deployment project in Visual Studio 2005, along with a few other tools, to create a single, self-extracting executable to install your managed software and prerequisites. I'm also going to provide a solution to one of the problems that I encountered when I recently attempted to create a self-extracting installer for one of my open source projects.
Introduction
Using a Setup and Deployment Project in Visual Studio, you can easily build a single Windows Installer file (.msi) that allows you to redistribute your custom software to your end-users, providing an automated and familiar setup experience. If your software depends on other software such as the Microsoft .NET Framework 2.0, as it probably will, then you can install them as prerequisites by having your Setup and Deployment project create a Generic Bootstrapper executable - Setup.exe. End-users should execute the bootstrapper instead of the .msi so that it will discover which dependencies are missing on the target machine, download and install them. The bootstrapper will then automatically run the .msi to install your software as long as the prerequisite installations were successful.
You can also develop custom Generic Bootstrapper packages and have them show up in Visual Studio's Prerequisites dialog, along with predefined packages such as the Microsoft .NET Framework 2.0 and Windows Installer 3.1. Custom packages can be configured to download the prerequisites from a website or they can be deployed along with the bootstrapper executable and your project's .msi file in their own sub-directories, which is extremely useful if the prerequisites are not available for download from some third-party website and if you don't have the means or desire to host them on your own web server.
User Experience
Having a bootstrapper to automatically install your software's dependencies is obviously useful, but your end-users will probably expect a single file to install your software and might be surprised to discover that they must download a Setup.exe file and an .msi file. You may also be tempted to deploy a Readme.txt file along with the installers to instruct users to run the Setup.exe program instead of the .msi. If you have added custom prerequisites to your bootstrapper then you may have to deploy them along with the installers as well if they aren't available for download from a web server. But since your end-users aren't going to be happy having to download several different files and then manually create the appropriate folder structure expected by Setup.exe, you're forced to zip all of the files and sub-directories together. An end-user must unzip the files, browse to the target directory in Windows Explorer and then double-click the Setup.exe file to start the installation.
All-In-One Deployment
So how about deploying a single, self-extracting executable that can dump all of the files into a temporary directory and then run the Setup.exe program automatically? There are several commercial products that can produce self-extracting zip files, but if you're like me you'd prefer a no-cost solution for something as simple, practical, and as seemingly common as having a single executable to install custom software.
Enter IExpress. Pre-installed on Windows systems, this program can create a self-extracting installer by compressing the files of your choice and may be configured to execute your Setup.exe bootstrapper upon extraction. The result can be distributed as a single, stand-alone file that contains the bootstrapper executable, any prerequisites that must be deployed along with your installer, and the .msi installer itself. That's right, pre-installed on Windows!
Start > Run > iexpress
The Directory Structure Problem
However, this amazing tool doesn't come without some pain. IExpress 2.0, the current version that ships with Windows Vista, doesn't preserve the folder structure of the files that it compresses. But the Setup.exe bootstrapper program is automatically built to look for each prerequisite that is not already being downloaded from a web server, in a local folder of the same name as the prerequisite itself. This obviously presents a problem when using IExpress since it will extract each prerequisite installer into the same temporary directory as the Setup.exe bootstrapper. Running a simple test reveals that the Setup.exe bootstrapper complains that it cannot locate one or more of the prerequisite installers.
But have no fear, there is a way. In order to better explain the process of using IExpress to extract and run the Setup.exe bootstrapper program with local file dependencies I'm going to use an example.
DocProject
DocProject is software that I've written to integrate Microsoft's managed API documenter, Sandcastle, into Visual Studio 2005. Up until the 1.6.0 Release Candidate of DocProject its installer shipped as a stand-alone Windows Installer file (.msi). But as of 1.6.0, a few of Microsoft's Primary Interop Assemblies for Visual Studio have become a prerequisite (namely, Microsoft.mshtml and stdole), which means that vs_piaredist.exe must be deployed along with the .msi. In order to ensure that end-users have Microsoft's redistributable assemblies installed on their systems before the DocProject installer is executed, I've create a Generic Bootstrapper package for vs_piaredist.exe that is required by DocProject's Setup and Deployment project.
As described in the introduction, DocProject's Setup and Deployment project builds a Setup.exe bootstrapper that checks for the prerequisites on the target machine and then, if the prerequisites aren't found, executes the vs_piaredist.exe file to install them. After the prerequisites are installed or skipped, the Setup.exe program then runs the .msi to install DocProject on the user's system.
When researching DocProject's prerequisites I discovered that Microsoft does not provide vs_piaredist.exe over the web, which means that I could have either zipped it with DocProject's installer, hosted it on my own web server, or figured out a way to include it into IExpress. I chose the latter since it requires the least amount of effort on mine and the user's part, but wasn't sure how it could work or if it was even possible at all.
Solution to the Directory Structure Problem
The Setup.exe bootstrapper is actually a generic executable that has a few null resources. When you build a Setup and Deployment project that has prerequisites, the MSBuild GenericBootstrapper Task is used to make a copy of the generic Setup.exe program. The copy is then loaded with a resource file that tells the bootstrapper how to install your program's prerequisites. Unfortunately, the MSBuild task doesn't provide the option to have the configuration resource use prerequisite installers found in the target directory, so you must manually update the appropriate resource file to remove the hard-coded path that looks for prerequisites in a sub-directory of the same name.
Sounds scary, but it's actually quite easy to do. Here are the instructions to create DocProject's installer:
- Build the Setup and Deployment project.
-
Open the Setup.exe program in Visual Studio's resource editor:
- File > Open > File (or Ctrl+O)
- Browse to the bin directory of the Setup and Deployment project and you'll find the Setup.exe file in the folder for the current configuration (e.g., Debug or Release), along with the other installer output.
- Double-click the resource named, SETUPCFG in the 41 folder
- Search for vs_piaredist\, exactly like that - with the trailing slash. Two (2) occurrences should be found. For each, make sure the entire vs_piaredist\ string is highlighted and press the Delete key to remove it from the resource.
- Save the resource file and the Setup.exe executable will be updated automatically.
-
Start > Run > iexpress
-
Create a new package by following the IExpress wizard's steps and make sure to include the following files:
- The Windows Installer file (.msi).
- The Setup.exe bootstrapper file.
- The vs_piaredist.exe file.
- Note: You should select the Store files using Long File Name inside Package option in one of the last wizard steps.
Step #4 is how to reconfigure the Setup.exe bootstrapper to look in the current directory for vs_piaredist.exe instead of in a subdirectory of the same name. We do this by simply removing the folder from the path in two different locations within the same resource file.
You should repeat step #4 for each of the local prerequisites that your Setup.exe bootstrapper will install, but instead of vs_piaredist\ use the name of the folder as it appears in your Setup and Deployment project's bin directory.
Conclusion
Visual Studio's Setup and Deployment project, the Generic Bootstrapper and IExpress are powerful tools that you can use to create installers for your custom software. Using IExpress to build a self-extracting installer that automatically runs your software's Setup.exe bootstrapper requires additional steps if the bootstrapper depends on prerequisite installers that are deployed with your software. By using Visual Studio's resource editor you can modify the Setup.exe file to look for prerequisites in the current directory. This allows you to build a self-extracting installer that contains all of your software's depencencies, providing a nice installation experience for your end-users.