Custom MSI authoring

Introduction

It has been 4 years since the last post about custom Login authoring. It was about ClickOnce. This time we will explore MSI authoring. To make it fun we will explore a real use case scenario and create Login MSI for CNRL. The reason we need custom build is that the solution that needs MSI does not have a login builder. In fact, it is so old it is still running on .net 2.0. But all we should care is we have all the ingredients to build it:

  1. App.WinClient.CNRLLogin - a custom login project for a solution.
  2. App.WinClient.CNLRLoginLibs - libraries needed to build our login project.
  3. App.MSBuild.CNLRLoginMSI - this article shows how to create this.
You will need up to date R4 solution to reproduce the build. Also when authoring MSBuild projects be sure to pick Archive when publishing your projects. If not you are risking to pollute the solution with invalid assemblies and executables.

Login Builder project

To start we will need a new login builder project. Open Login Builder and press New Login Client... button in a toolbar. Let us name it CNRL. Since App.WinClient.CNRLLogin already includes predefined Settings and Login Form Design we do not need to fill it. We need to open Custom build steps tab and press Insert Installer Steps. Your custom build steps should look exaclty like in the image below.

Here SetEntryProjName action defines what project is used to generate Build service Entry Point. Sys.MSBuild.LoginMSI contains all the build scripts to prepare a fresh MSI for you, but it uses Sys.WinClient.Login to do that. So we need to clone that project and create our own Entry point project. Let us name it App.MSBuild.CNLRLoginMSI (you can download the finished version here). Since we know our Entry project name we can update Custom build steps to reflect that:

This concludes all the preparation work we needed to do in Login Builder. Now we need to adapt App.MSBuild.CNLRLoginMSI to fit our needs.

Build Service Entry point

Let us start our customization with a vital part of the entry point project, settings.xml. We do not need to include Sys.WinClient.login project but instead we need to include our custom login project: App.WinClient.CNRLLogin. Sys.MSBuild.Targets contains common build targets so it must stay. Finally, we need to include App.WinClient.CNLRLoginLibs archive library project to ensure our App.WinClient.CNRLLogin project builds on the Build Service side. The updated settings.xml should look like this:

Next we need to change login project name in root.targets. Original values from Sys.MSBuild.LoginMSI:

..\..\WinProjects\Sys.WinClient.login $(LoginProjectPath)\MarketMaker.vbproj

Should be changed to:

..\..\WinProjects\App.WinClient.CNRLLogin $(LoginProjectPath)\App.WinClient.Login.vbproj

Changes we made are due to different WinProject name and different *.vbproj file name.

Next we change targets being called in applyconfiguration target. Original:

Changed to:

Here we do not call updateappconfig and writeinfo but call only readsettings and brand.

  • readsettings will ensure that we read all the critical settings like MSI Upgrade code, AssemblyName, Product Title and so on.
  • brand will copy icon and branded login header footer images to the presumed login resources folder.
If you need to know more about what is being done, you can sneak a peek into Sys.MSBuild.Targets Library.

Next, we will do some minimal maintenance to static.wxs. This file contains a definition of how to prepare your MSI using WIX Toolset, a defacto MSI authoring toolkit. As mentioned, this solution uses .net 2.0 so we do not need the part that ensures .net 4.5 is already installed. The xml below should be removed from static.wxs:

With this removal, we have concluded doing our customization! Publish the project as an archive and it should now be possible to build Using Custom Build....

The Custom build

Once every customization is in place and published, we can start building our Custom MSI:

When built, LoginInstaller.1.0.1.0.zip file should be added to the history tab:

The resulting installer will include all the required third-party libraries that were referenced by a custom login project. You can verify that by installing resulting MSI and navigating to C:\Program Files (x86)\CNRL folder:

This flexibility is achieved by using HeatDirectory Task. In short, we harvest all the artifacts from the bin folder and turns them into a *.wxs file containing a component group. This component group is included in static.wxs ahead of time with installer_harvest id:

Here I have bundled all the ingredients you need to reproduce the build.

Conclusion

It is not too hard to author a custom build with login builder. One just needs a custom entry point project (App.MSBuild.CNLRLoginMSI in this article) and backing projects (App.WinClient.CNRLLogin and App.WinClient.CNLRLoginLibs in this article). Most of the work has already been done and you just need to clone one of the Sys.MSBuild.% projects and tweak it, as we did here. Have a productive time authoring your custom builds.