Monday, 18 August 2014

Product Versions in MSI installers created with WIX - part 1

I must confess that in the past I used to do this manually or not at all (loud gasps) as I've never had a fully functioning CI environment but, this has changed recently so here it goes.

In essence the challenge is to change the version number of the installer every time a new build is done, so that the build number is reflected in both Windows (Control Panel -> Programs and Features ) and the file itself, e.g. installer.1.0.0.0.msi

There are two main ways of doing this, that I know of:
  • Pass the build number to the Wix Installer.
  • Get the build number from a library or executable.

In this post, I will discuss the first way, all changes unless stated are made to the wix project file (wixproj extension), so you will need to unload the project from Visual Studio or use another editor to make these changes.

We need a Property to hold the version number, which appropriately is called VersionNumber, I've made sure that this is populated with a default value, in case the build is done from Visual Studio.
<VersionNumber Condition=" '$(VersionNumber)' == '' ">0.0.0.0</VersionNumber>
I then appended the version number to the installer:
<OutputName>Installer.$(VersionNumber)</OutputName>
We then need to add a preprocessor variable to each build configuration, I've called it MSIVersion, as this is the version of the msi package:
<DefineConstants>MSIVersion=$(VersionNumber)</DefineConstants>
and finally we use this preprocessor variable in the product definition in the Product.wxs file.
<Product Id="01010101-deaf-beef-c0de-863f442f44fb" Name="MROAE" Language="1033" Version="$(var.MSIVersion)" Manufacturer="MROAE" UpgradeCode="01010101-daaa-beef-c0de-863f442f44fb">
This solution can now be build with the following command:
msbuild mysolution.sln /p:VersionNumber=1.0.0.1
A sample wixproj file can be found below with changes detailed above:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <PackageVersion>3.8</PackageVersion>
    <ProjectGuid>{02af16dd-0000-0000-0000-d60ba5af40cc}</ProjectGuid>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputType>Package</OutputType>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <VersionNumber Condition=" '$(VersionNumber)' == '' ">0.0.0.0</VersionNumber>
    <Name>Installer</Name>
    <OutputName>Installer.$(VersionNumber)</OutputName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>Debug;MSIVersion=$(VersionNumber)</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>MSIVersion=$(VersionNumber)</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Service.wxs" />
    <Compile Include="Product.wxs" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\Service\Service.csproj">
      <Name>Service</Name>
      <Project>{000c956c-0000-0000-0000-970884f34476}</Project>
      <Private>True</Private>
      <DoNotHarvest>True</DoNotHarvest>
      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
      <RefTargetDir>INSTALLFOLDER</RefTargetDir>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <Content Include="Icons\Product.ico" />
     </ItemGroup>
  <ItemGroup>
    <Folder Include="Icons" />
  </ItemGroup>
  <ItemGroup>
    <WixExtension Include="WixUtilExtension">
      <HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
      <Name>WixUtilExtension</Name>
    </WixExtension>
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" />
  <!--
 To modify your build process, add your task inside one of the targets below and uncomment it.
 Other similar extension points exist, see Wix.targets.
 <Target Name="BeforeBuild">
 </Target>
 <Target Name="AfterBuild">
 </Target>
 -->
</Project>

And the Product File(product.wxs)

<Product Id="01010101-deaf-beef-c0de-8f3f4a2f44fb" Name="MROAE" Language="1033"
Version="$(var.MSIVersion)" Manufacturer="MROAE" 
UpgradeCode="01010101-daaa-beef-c0de-8f3f4a42f44b">

No comments:

Post a Comment