I will create a simple windows installer. I do not pretend you should use it or the code bellow is a generic solution for building a windows service installers. The full source code is available here
Currently the most flexible free way for creating installers is WiX. The WiX installer adds several project templates to Visual Studio and also adds MSBuild targets for WiX support.
From Visual Studio create Windows Installer XML => Setup Project. I want to create a setup project for a windows service project and that windows service project contains dependencies. The main problem is how to handle project dependencies effectively. I could simply add all references by hand and write them in Product.wxs file but that is not a good solution for me. So I will directly use heat.exe which is part of the WiX tools to collect all files needed and the output result will be Product.wxs with all the dependencies. Heat will be called before building the setup/installer project on PreBuildEvent. This tool has a lot of parameters and I will not explain what they do here but there are some mandatory like target directory or output. The first important parameter is the directory which will be scanned by heat but the directory is also used for building the correct paths for all files referenced in Product.wxs. In this example all projects output the assemblies in a common bin folder. Defining that directory and passing it as a parameter is done directly within the project file (define SourceOutput under the common PropertyGroup; define a compiler constant SourceOutput=$(SourceOutput); pass the constant like “heat.exe” dir $(SourceOutput) -var var.SourceOutput). At this point all files under the bin folder will be added but heat has a way for transforming the results using *.xslt. The PreBuildEvent is now complete: <PreBuildEvent>”$(WIX)bin\heat.exe” dir $(SourceOutput) -cg References -srd -o $(ProjectDir)Product.wxs -nologo -gg -g1 -scom -sreg -t $(ProjectDir)Transformer.xslt -var var.SourceOutput</PreBuildEvent>
Essentially the Transformer.xslt is the place where all the changes must be done because the Product.wxs file will be overwritten every time the solution is built (-o $(ProjectDir)Product.wxs). After adding the Transformer.xslt to the project all the infrastructure is done and the project file looks like this:
WiX has the notion of Product, Feature, Component. I see it like this way. Product is the main place for configuring the installer package. It also holds one or more Features. Defining a Feature enables the option whether to install or not install a particular feature at setup time. Component describes the content of the Feature and this is the place which is important.
The first thing to do is to change the variable section <xsl:variable>.
In the bin folder there are other projects’ assemblies which should not be in the final installer package. I want only the windows service output directory NMSD.StatsD-PerfMon to be added. Easy. The template called Component1_ReferencesTemplate filters the directories but you have to manually write the name of the desired directory in the foreach statement: and (contains(@Source, ‘NMSD.StatsD-PerfMon’))
After heat has finished its job all the file tags in Product.wxs will have a property called KeyPath which is wrong. Only the windows service entry point NMSD.StatsD-PerfMon.exe must contain that property. The xslt template at the bottom corrects this but you have to manually write the name of the file which will contain the KeyPath property.
In my case I did an installer with two features. Both features were developed heavily and I did several releases/deploys using the installer and I did not edit the xslt even once. I just do rebuild with psake and everything is working.