Friday, 9 November 2012

Converting a Visual Studio Setup Project to Wix


Anyone who’s using Visual Studio 2012 and either opened up an old solution with a Setup Project (.vdproj) or created a new solution and looked for the setup project under project types will know it’s no longer there and no longer supported. This is not actually that surprising since TFS Build Server and MSBuild doesn’t support the legacy .vdproj files any way.

Wix is the recommended alternative; itis very powerful, but quite complicated to work with and there is currently no GUI.

The .vdproj can’t be converted directly, however one of the wix tools called dark can be used to decompile msi files into wxs xml format.

This is a step by step procedure for converting an MSI with an exe, a number of DLLs and files into a Wix project.

1. If you haven’t got Wix, install it and add a Wix project to your solution.

2. Decompile the msi with the following command line:

c:\Program Files (x86)\WiX Toolset v3.6\bin>dark c:\temp\setup.msi -o c:\temp\setup.wxs

Dark will output results like this, there will be a load of warnings like this:

Windows Installer Xml Decompiler version 3.6.3303.0
Copyright (C) Outercurve Foundation. All rights reserved.

setup.msi
c:\temp\setup.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 Windows Installer XML 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:\temp\setup.msi : warning DARK1062 : The ModuleSignature table can only be represented in WindowsInstaller XML for merge modules.  The information in this table will be left out of the decompiled output.
c:\temp\setup.msi : warning DARK1062 : The ModuleComponents table can only be represented in Windows Installer XML for merge modules.  The information in this table will be left out of the decompiledoutput.
c:\temp\setup.msi : warning DARK1066 : The MsiPatchHeaders table is added to the install package bya 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:\temp\setup.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:\temp\setup.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.

3. Export binaries using dark.exe:
c:\Program Files (x86)\WiX Toolset v3.6\bin>dark c:\temp\setup.msi -x c:\temp

4. Rename anything that sounds like an icon or bitmap in the outputted ‘Binary’ folder to have a .bmp suffix, I had:
  • DefBannerBitmap
  • NewFldrBtn
  • UpFldrBtn

These should be .ibd files:
  • MSVBDPCADLL
  • VSDNETCFG

The icon in the ‘Icon’ folder can be renamed .ico

Copy these folders into the WIX project, include them and set as resources.

5. Fix binary paths from

<Binary Id="MSVBDPCADLL" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
        <Binary Id="VSDNETCFG" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
        <Binary Id="DefBannerBitmap" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
        <Binary Id="UpFldrBtn" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />
        <Binary Id="NewFldrBtn" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />

To:

<Binary Id="MSVBDPCADLL" SourceFile="Binary\MSVBDPCADLL.ibd" />
    <Binary Id="VSDNETCFG" SourceFile="Binary\VSDNETCFG.ibd" />
    <Binary Id="DefBannerBitmap" SourceFile="Binary\DefBannerBitmap.bmp" />
    <Binary Id="UpFldrBtn" SourceFile="Binary\UpFldrBtn.bmp" />
    <Binary Id="NewFldrBtn" SourceFile="Binary\NewFldrBtn.bmp" />

And

<Icon Id="_7BBE63EC1B23A31B9D3734.exe" SourceFile="FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES" />

To:

<Icon Id="_7BBE63EC1B23A31B9D3734.exe" SourceFile="Icon\_7BBE63EC1B23A31B9D3734.ico" />

6. Fix project references by adding references to the required projects in the solution like you would in any normal project and then fix the binary components like this (DLLs are similar to EXEs):

<Component Id="C__EFA30D8EEF7020387C8D684F42EDADC6" Guid="{BA9BC921-7529-B2AF-D64D-ABF58AAF77AD}">
                <File Id="_EFA30D8EEF7020387C8D684F42EDADC6" Name="MyApplication.exe" KeyPath="yes" ShortName="MYAPPL~1.EXE" Assembly=".net" AssemblyManifest="_EFA30D8EEF7020387C8D684F42EDADC6" AssemblyApplication="_EFA30D8EEF7020387C8D684F42EDADC6" DiskId="1" Source="SourceDir\File\_EFA30D8EEF7020387C8D684F42EDADC6" />
                <Shortcut Id="_1EE6E64055BE47E2AD4588E6B6AC87EC" Directory="_380EF96A89404298A858064DE3EC207A" Name="MyApplication" ShortName="MYAPPLICATIONL~1" Icon="_7BBE63EC1B23A31B9D3734.exe" IconIndex="0" Show="normal" WorkingDirectory="TARGETDIR" Advertise="yes" />
            </Component>

To:

<Component Id="C__EFA30D8EEF7020387C8D684F42EDADC6" Guid="{BA9BC921-7529-B2AF-D64D-ABF58AAF77AD}">
        <File Id="_EFA30D8EEF7020387C8D684F42EDADC6" Name="MyApplication.exe" KeyPath="yes" ShortName="MYAPPL~1.EXE" Assembly=".net" AssemblyManifest="_EFA30D8EEF7020387C8D684F42EDADC6" AssemblyApplication="_EFA30D8EEF7020387C8D684F42EDADC6" DiskId="1" Source="$(var.MyApplication.TargetPath)" />
        <Shortcut Id="_1EE6E64055BE47E2AD4588E6B6AC87EC" Directory="_380EF96A89404298A858064DE3EC207A" Name="MyApplication" ShortName="MYAPPL~1" Icon="_7BBE63EC1B23A31B9D3734.ico" IconIndex="0" Show="normal" WorkingDirectory="TARGETDIR" Advertise="yes" />
      </Component>

7. Fix file components like this:

<Component Id="C__0BDFAFE635E591014F851368D952F145" Guid="{BE51E0B1-FFFA-CB90-0B48-D6A70E66312E}">
                <File Id="_0BDFAFE635E591014F851368D952F145" Name="Settings.csv" KeyPath="yes" ShortName="SETTINGS.CSV" DiskId="1" Source="SourceDir\File\_0BDFAFE635E591014F851368D952F145" />
            </Component>
To:

<Component Id="C__0BDFAFE635E591014F851368D952F145" Guid="{BE51E0B1-FFFA-CB90-0B48-D6A70E66312E}">
        <File Id="_0BDFAFE635E591014F851368D952F145" Name="Settings.csv" KeyPath="yes" ShortName="SETTINGS.CSV" DiskId="1" Source="$(var.MyApplication.TargetDir)" />
      </Component>

8. Now build and fix any errors. Installers can contain many different components and features so will vary in their complexity to get working.