Wix Rollin’
What a difference a few hours makes. Yesterday afternoon I was feeling mightily peeved off that Microsoft had still not put any support in MSBuild for building Visual Studio Deployment Projects. I was with the folks in the various forums, blogs and other dark places where we all visit who cried ‘foul!’ and ‘unfair’ and MS’s decision.
That was however until I rediscovered WiX – Windows Installer XML.
I had seen WiX once before (quite some time before) and at the time I dismissed it as ‘Something I might care about later’. My TFS Build at the time were creating libraries or other code that didn’t required an installer so I really paid it no heed. Well, yesterday was the day that I cared about it.
MS obviously have put a lot of faith in WiX – I read somewhere that they even use it internally to build the Office 2007 installer – if this is indeed the case then it’s no small feat. The installers I needed to create where by no-means on the same level so I figured at that time, when in Rome.
Now granted WiX is a bit of a learning curve but there are tools out there that make your life easy – especially when you’ve already got a .vdproj that you need to WiXify. When converting existing deployment projects there’s a slight reverse around face in that it actually makes more sense to start with the end-project and work your way back to a new installer than attempt to build a new WiX project from scratch.
So, in an attempt to help clarify a few steps, here’s my trip down converting an existing deployment project into a new fangled WiX project – complete with the need to reference binaries as part of the MS Enterprise Application block 4.1.
Caveat Emptor: I’m not saying that these steps are the most efficient – however they did work for me!
NB: I was using the WiX Beta 3 build 4805.0 to create my packages and Visual Studio 2008 Team Suite along with TFS 2008 to create my projects and builds.
Step 1: Reverse engineer to deployment project.
Sure you have the source, so why reverse engineer anything? Well, in our case the project builds an MSI file which is pretty easy to decompile given the tools available in WiX. So, first off copy the MSI to a temporary work area and execute the Dark WiX executable to decompile the MSI into it’s constituent parts – and create a WiX project file as a result.
C:\tmp\1 Day\WiX>"C:\Program Files\Windows Installer XML v3\bin\dark.exe" -x Binary LogProcessorServiceSetup.msi LogProcessorServiceSetup.Wxs Microsoft (R) Windows Installer Xml Decompiler version 3.0.4805.0Copyright (C) Microsoft Corporation. All rights reserved. LogProcessorServiceSetup.msiC:\tmp\1 Day\WiX\LogProcessorServiceSetup.msi : warning DARK1060 : The _VsdLaunchCondition table is being decompiled as a custom table.dark.exe : warning DARK1065 : The AdvtUISequence table is not supported by the WiX toolset because it has been deprecated by the Windows Installer team. Any information in this table will be left out of the decompiled output.C:\tmp\1 Day\WiX\LogProcessorServiceSetup.msi : warning DARK1062 : The ModuleSignature table can only be represented in WiX for merge modules. The information in this table will be left out of the decompiled output.C:\tmp\1 Day\WiX\LogProcessorServiceSetup.msi : warning DARK1062 : The ModuleComponents table can only be represented in WiX for merge modules. The information in this table willbe left out of the decompiled output.C:\tmp\1 Day\WiX\LogProcessorServiceSetup.msi : warning DARK1066 : The MsiPatchHeaders table is added to the install package by a transform from a patch package (.msp) and not authored directly into an install package (.msi). The information in this table will be left out of the decompiled output.C:\tmp\1 Day\WiX\LogProcessorServiceSetup.msi : warning DARK1066 : The Patch table is added to the install package by a transform from a patch package (.msp) and not authored directly into an install package (.msi). The information in this table will be left out of the decompiled output.C:\tmp\1 Day\WiX\LogProcessorServiceSetup.msi : warning DARK1066 : The PatchPackage table is added to the install package by a transform from a patch package (.msp) and not authored directly into an install package (.msi). The information in this table will be left out of the decompiled output.dark.exe : warning DARK1058 : The AdvtExecuteSequence table contains an action 'MsiUnpublishAssemblies' which is not allowed in this table. If this is a standard action then it is not valid for this table, if it is a custom action or dialog then this table does not accept actions of that type. This action will be left out of the decompiled output.C:\tmp\1 Day\WiX> |
Getting a directory listing gives us the output of the decompilation process.
C:\tmp\1 Day\WiX>dir /s Volume in drive C has no label. Volume Serial Number is 045E-5666 Directory of C:\tmp\1 Day\WiX 02/10/2009 10:39 AM <DIR> .02/10/2009 10:39 AM <DIR> ..02/10/2009 10:39 AM <DIR> Binary02/10/2009 10:36 AM 434,688 LogProcessorServiceSetup.msi02/10/2009 10:39 AM 91,008 LogProcessorServiceSetup.Wxs 2 File(s) 525,696 bytes Directory of C:\tmp\1 Day\WiX\Binary 02/10/2009 10:39 AM <DIR> .02/10/2009 10:39 AM <DIR> ..02/10/2009 10:39 AM <DIR> Binary02/10/2009 10:39 AM <DIR> File 0 File(s) 0 bytes Directory of C:\tmp\1 Day\WiX\Binary\Binary 02/10/2009 10:39 AM <DIR> .02/10/2009 10:39 AM <DIR> ..02/10/2009 10:39 AM 5,088 DefBannerBitmap02/10/2009 10:39 AM 65,032 InstallUtil02/10/2009 10:39 AM 227,832 MSVBDPCADLL02/10/2009 10:39 AM 318 NewFldrBtn02/10/2009 10:39 AM 318 UpFldrBtn02/10/2009 10:39 AM 11,225 VSDNETCFG 6 File(s) 309,813 bytes Directory of C:\tmp\1 Day\WiX\Binary\File 02/10/2009 10:39 AM <DIR> .02/10/2009 10:39 AM <DIR> ..02/10/2009 10:36 AM 7,680 _0A137FFDF05A958D558EC9E2DC48F39A02/06/2009 07:48 AM 1,326 _2CB35E650D766290C1E57911DE7343FA02/10/2009 10:36 AM 9,216 _35C91406817D7569FFBF7DDCC6ADDC5902/10/2009 10:35 AM 13,312 _4EE2E5745FE6A5B237002FB1A0E247F102/10/2009 10:36 AM 13,312 _517D39ACB53634B59852C8E153B41E9802/10/2009 10:35 AM 16,384 _6C0EF8CC468814B88806785D8F53190502/10/2009 10:35 AM 10,240 _7D696D868B909DC126A1AB2EDED8BEE102/10/2009 10:35 AM 10,240 _933F30ADC0DFD69EB551623235879B2102/10/2009 10:36 AM 14,336 _C91E465D8BB437D741ED4B41A36F6385 9 File(s) 96,046 bytes Total Files Listed: 17 File(s) 931,555 bytes 11 Dir(s) 18,724,569,088 bytes free C:\tmp\1 Day\WiX> |
The Files under Binary\File are the actual DLL’s etc that have been packaged up and as such can be safely disposed of (we have the originals still available to us within the VS Solution. Binary\Binary contains the various support files that are required to run the installer. Note that the files have no extension – that’s perfectly fine and can be left as is.
Step 2: Create a new WiX project in the solution.
WiX comes with a few bonus tracks; one of which is Votive. Votive is essentially a WiX project type for Visual Studio and gives you not only the ability to edit the files utilizing IntelliSense, but to set up project properties as well.
Once built, you should see something akin to the following in your Solution Explorer window:
First thing we need to do is gut the created Product.Wxs and replace it with the one Dark.exe generated for us. Make sure the Product.Wxs file is open in the VS Editor then paste the text straight in, overwriting everything.
Step 3: Update the support binaries
If you examine the newly pasted content you’ll come across the first area that we need to address; the support files are currently in the wrong location.
To resolve this, create a new Binary folder in the project and copy the contents Binary\Binary folder over to the solution then update the SourceFile values accordingly:
Step 4: Update the package files
We’re getting close now – however we still don’t yet have something that will build correctly for the simple reason the references are shot. So they will need to be updated next.
Take a look further down the Wxs file and you’ll come across the area of concern:
You’ll notice that the Source value is set to a GUID that refers back to one of the files we threw away after executing Dark.exe. Fortunately we don’t need to translate the filename as it’s provided for us is the Name value. All we need to do here then is replace the folder name and file with a relative path where we’re taking the files from. In my case here I stored the DLL’s used in a folder called Common\Bin. So one of my entries would now look like:
Step 5: Referencing external libraries
That takes care of our files, but what of other external files – in my case use of the Enterprise Application Block. In order to make the build transparent across both Visual Studio and TFS I needed a better route of referencing the correct binaries. This is where the use of a Preprocessor directive comes into play.
Open up the WiX project properties and select the ‘All Configurations’ configuration:
The Enterprise Application 4.1 block always installs itself into %ProgramFiles\Microsoft Enterprise Library 4.1 – October 2008 so we can use that to create our variable. Enter the following in the first text box (Preprocessor variables):
MSEntBlock41=$(ProgramFiles)\Microsoft Enterprise Library 4.1 – October 2008\Bin
Since VS 2008 (like 2005) uses MSBuild behind the scenes, this will expand to reference the correct location. By using an environment variable we avoid situations where the C: drive may not the the default drive on the build server.
Now we need to simply reference this Preprocessor variable in the Wxs script using the form $(var.MSEntBlock41):
Step 6: Dealing with the registry
Whilst the Wxs generated by Dark.exe is valid, it apparently does not meet it’s own standards – namely registry access.
For example, here’s what Dark.exe generated:
However the correct format required is:
Notice the use of a referencing the windir environment variable. We could have used a Preprocessor variable here as well – I simply wanted to demonstrate using both sorts.
Step 7: App.Config
The final change we need to make is to reference the applications App.config file. Normally the deployment project handles this transformation for us but we need to perform the step via WiX. However it’s easy enough:
Step 8: Updating the build configuration
The final step required is to ensure TFS Build picks up the new project. The set up projects created by WiX seem to target Chipsets; as a result I had to update the Configuration Manager to ensure that they were included in a ‘Any CPU’ build. This is probably not best practice but will work for me (your mileage may vary)
Further reading:
WiX Tutorial : http://www.tramontana.co.hu/wix/
Preprocessor variables: http://wix.sourceforge.net/manual-wix2/preprocessor.htm
WiX v3.4805.0, TFS 2008 SP1, VS 2008 SP1
Thanks for this tutorial