Migrating Visual Studio plugin setup project (.vdproj) to wix – Step by Step Approach

Microsoft decided to remove .vdproj in Visual Studio 2012 (ah…Microsoft -.-). The installation project for one of our visual studio plugins is the casualty of this decision. Hence, I was assigned the task to find/export the current .vdproj into an alternative source. So I decided to give Wix a go. Wix itself is not so bad; it has a good support for Visual Studio (comes with its own project template and all) but the documentation is fairly lacking. Anyway, here’s the step to step approach to migrate pre VS 2012 setup project to wix!

1. Install Wix : http://wixtoolset.org/

2. Create a new wix setup project.

3. Add plugin project by right clicking references on wix project. Choose “Add References” – “Projects” tab – Your VS plugin project.

4. Change the Product.wxs into :

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  <?define YOURCOMPANY_DLL_FILE_COMPONENT_GUID = "2164B056-41E1-4D49-A244-B3D43BFFA741" ?>
  <?define VS2010_ADDIN_FILE_COMPONENT_GUID = "5505429F-4C92-4309-8EDC-BACE4F36EFE7" ?>
  <?define VS2012_ADDIN_FILE_COMPONENT_GUID = "F03C7CDC-6259-4C50-B93D-1B63DA785922" ?>
  <?define APP_NAME = "YOURCOMPANY SCD UAT Build" ?>
  <?define DEFAULT_GROUP_NAME = "YOURCOMPANY" ?>
  <?define DEST_SUB_DIR = "YOURCOMPANY APP NAME" ?>
  <?define DLL_FILE_NAME_YOURCOMPANY = "YOURCOMPANYVsPlugin.dll" ?>
  <?define ADDIN_XML_FILE_NAME = "YOURCOMPANYVsPlugin.Addin" ?>
  <?define CONNECT_CLASS_FULL_NAME = "YOURCOMPANYVsPlugin.Connect" ?>

  <!--PROTIP: Ignore all the remove file error when building this project-its actually a warning, not an error. Project will still build in the bin folder regardless of error.-->   
  <Product Id="*" Name="$(var.APP_NAME)" Language="1033" Version="1.0.0.0" Manufacturer="Microsoft" UpgradeCode="8d5bf66b-35d6-4201-ac9c-f2b5837ded5c">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <!--PROTIP: Flip embedcab to false when debugging so we can see what goes in the package-->
    <MediaTemplate EmbedCab="yes" />

    <Property Id="VS2010INSTALLATIONFOLDER" Secure="yes">
      <RegistrySearch Id="VS2010InstallationFolderRegistrySearchId" Type="raw"
                      Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\10.0" Name="InstallDir"></RegistrySearch>
    </Property>
    <Property Id="VS2012INSTALLATIONFOLDER" Secure="yes">
      <RegistrySearch Id="VS2012InstallationFolderRegistrySearchId" Type="raw"
                      Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0" Name="InstallDir"></RegistrySearch>
    </Property>

    <!-- Launch condition: check that some Visual Studio version is present when the installing.
           The OR'ed Installed variable ensures that the condition is always true when uninstalling, because we don't
           need to check that Visual Studio is present when uninstalling.
      -->
    <Condition Message="This add-in requires Visual Studio 2005, 2008 or 2010 or 2012.">
      Installed OR VS2010INSTALLATIONFOLDER OR VS2012INSTALLATIONFOLDER
    </Condition>

    <Feature Id="VSCommonFeatureId" Title="$(var.APP_NAME)" Level="1" AllowAdvertise="no"
           Description="Common files of the add-in." Display="expand" Absent="disallow">

      <!-- This child feature is the add-in for Visual Studio 2010 -->
      <Feature Id="VS2010InstallationFeatureId" Title="Visual Studio 2010"
               Description="Installs the add-in for Visual Studio 2010." Level="1" AllowAdvertise="no">

        <!-- The feature is hidden (Level is set to 0) when Visual Studio 2010 is not installed and
                 it is the first installation (not in maintenance mode)
            -->
        <Condition Level="0">NOT Installed AND NOT VS2010INSTALLATIONFOLDER</Condition>

        <!-- Its components are the add-in dll and the .AddIn XML file for Visual Studio 2010 -->
        <ComponentRef Id="YOURCOMPANYDllFileComponentId" />
        <ComponentRef Id="VS2010AddInFileComponentId" />

      </Feature>

      <!-- This child feature is the add-in for Visual Studio 2012 -->
      <Feature Id="VS2012InstallationFeatureId" Title="Visual Studio 2012"
               Description="Installs the add-in for Visual Studio 2012." Level="1" AllowAdvertise="no">

        <Condition Level="0">NOT Installed AND NOT VS2012INSTALLATIONFOLDER</Condition>

        <ComponentRef Id="YOURCOMPANYDllFileComponentId" />
        <ComponentRef Id="VS2012AddInFileComponentId" />
        <ComponentRef Id="UninstallMSDir" />
        <ComponentRef Id="UninstallVSDir" />
        <ComponentRef Id="UninstallDir100Id" />
        <ComponentRef Id="UninstallDir101Id" />

      </Feature>


    </Feature>

    <UIRef Id="WixUI_FeatureTree" />

  </Product>

  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="YOURCOMPANYFolder" Name="$(var.DEFAULT_GROUP_NAME)">
          <Directory Id="YOURCOMPANYDllFolder" Name="$(var.DEST_SUB_DIR)" />
        </Directory>
      </Directory>
      <Directory Id="AppDataFolder">
        <Directory Id="MicrosoftDirId" Name="Microsoft">
          <Component Id="UninstallMSDir" Guid="3AEE8422-A8D1-4EEB-B1EE-B96283C24ED4">
            <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\UninstallMSDir" Name="Installed" Type="integer"
                       Value="1" KeyPath="yes"/>
            <RemoveFolder Id="UninstallMSDIr" On ="uninstall"/>
          </Component>
          <Directory Id="VisualStudioDirId" Name="VisualStudio">
            <Component Id="UninstallVSDir" Guid="F4761C9F-7D03-4AC6-AB1E-843B89B25564">
              <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\UninstallVSDi" Name="Installed" Type="integer"
                       Value="1" KeyPath="yes"/>
              <RemoveFolder Id="UninstallVSDir" On ="uninstall"/>
            </Component>
            <Directory Id="Dir100Id" Name="10.0">
              <Component Id="UninstallDir100Id" Guid="C55597B3-8D10-482F-B0A3-7C1693FFFCC7">
                <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\UninstallDir100Id" Name="Installed" Type="integer"
                       Value="1" KeyPath="yes"/>
                <RemoveFolder Id="UninstallDir100Id" On ="uninstall"/>
              </Component>
              <Directory Id="Dir100AddInsId" Name="AddIns">
              </Directory>
            </Directory>
            <Directory Id="Dir101Id" Name="11.0">
              <Component Id="UninstallDir101Id" Guid="70B4E029-EF4E-45AA-A393-7E3B6CDC9BC2">
                <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\UninstallDir101Id" Name="Installed" Type="integer"
                       Value="1" KeyPath="yes"/>
                <RemoveFolder Id="UninstallDir101Id" On ="uninstall"/>
              </Component>
              <Directory Id="Dir101AddInsId" Name="AddIns">
              </Directory>
            </Directory>
          </Directory>
        </Directory>
      </Directory>
    </Directory>
  </Fragment>

  <Fragment>
    <ComponentGroup Id="ProductComponents">
      <Component Id="YOURCOMPANYDllFileComponentId" Guid="$(var.YOURCOMPANY_DLL_FILE_COMPONENT_GUID)" Directory="YOURCOMPANYDllFolder">

        <File Id="YOURCOMPANYDllFileId" Name="$(var.DLL_FILE_NAME_YOURCOMPANY)" Vital="yes" DiskId="1" Source="$(var.YOURCOMPANYVsPlugin.TargetPath)" />

        <!-- This registry entry used as KeyPath is required to avoid the following warnings:
                  ICE38: Component <x> installs to user profile. It must use a registry key under HKCU as its KeyPath not a file.
                  -->
        <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\YOURCOMPANYVsPluginDllFile" Name="Installed" Type="integer"
                       Value="1" KeyPath="yes"/>
        <RemoveFolder Id="RemoveYOURCOMPANYDllFileComponentId"
                                              On="uninstall" />

      </Component>

      <Component Id="VS2012AddInFileComponentId" Directory="Dir101AddInsId" Guid="$(var.VS2012_ADDIN_FILE_COMPONENT_GUID)">
        <!-- Copy the .AddIn file to the folder -->
        <File Id="VS2012AddInFileId" Name="$(var.ADDIN_XML_FILE_NAME)" Vital="yes" DiskId="1"
              Source="$(var.YOURCOMPANYVsPlugin.ProjectDir)$(var.ADDIN_XML_FILE_NAME)" />
        <!-- Modify the Version XML element inside the .AddIn file whose Id is VS2012AddInFileId
                                to set the value "10.0" (which is the version of VS 2012) -->
        <util:XmlFile Id="VS2012SetVersionElement" Action="setValue" File="[#VS2012AddInFileId]"
                      ElementPath="/Extensibility/HostApplication/Version" Value="11.0" Sequence="1" />
        <!-- Modify the Assembly XML element inside the .AddIn file whose Id is VS2012AddInFileId
                                to set value of the file whose Id is YOURCOMPANYDllFileId -->
        <util:XmlFile Id="VS2012SetAssemblyElement" Action="setValue" File="[#VS2012AddInFileId]"
                      ElementPath="/Extensibility/Addin/Assembly" Value="[#YOURCOMPANYDllFileId]" Sequence="1" />
        <!-- Modify the FullClassName XML element inside the .AddIn file whose Id is VS2012AddInFileId
                                to set value of the variable CONNECT_CLASS_FULL_NAME -->
        <util:XmlFile Id="VS2012SetFullClassNameElement" Action="setValue" File="[#VS2012AddInFileId]"
                      ElementPath="/Extensibility/Addin/FullClassName"
                      Value="$(var.CONNECT_CLASS_FULL_NAME)" Sequence="1" />
        <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\VS2012AddInFile" Name="Installed"
               Type="integer" Value="1" KeyPath="yes"/>
        <RemoveFolder Id="RemoveVS2012AddInFileComponentId"
                                      On="uninstall" />
      </Component>

      <Component Id="VS2010AddInFileComponentId" Guid="$(var.VS2010_ADDIN_FILE_COMPONENT_GUID)" Directory="Dir100AddInsId">
        <File Id="VS2010AddInFileId" Name="$(var.ADDIN_XML_FILE_NAME)" Vital="yes" DiskId="1"
              Source="$(var.YOURCOMPANYVsPlugin.ProjectDir)$(var.ADDIN_XML_FILE_NAME)" />
        <util:XmlFile Id="VS2010SetVersionElement" Action="setValue" File="[#VS2010AddInFileId]"
                      ElementPath="/Extensibility/HostApplication/Version" Value="10.0" Sequence="1" />
        <util:XmlFile Id="VS2010SetAssemblyElement" Action="setValue" File="[#VS2010AddInFileId]"
                     ElementPath="/Extensibility/Addin/Assembly" Value="[#YOURCOMPANYDllFileId]" Sequence="1" />
        <util:XmlFile Id="VS2010SetFullClassNameElement" Action="setValue" File="[#VS2010AddInFileId]"
                      ElementPath="/Extensibility/Addin/FullClassName"
                      Value="$(var.CONNECT_CLASS_FULL_NAME)" Sequence="1" />
        <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\VS2010AddInFile" Name="Installed"
                       Type="integer" Value="1" KeyPath="yes"/>
        <RemoveFolder Id="RemoveVS2010AddInFileComponentId"
                                      On="uninstall" />

      </Component>

    </ComponentGroup>
  </Fragment>

</Wix>

Remember to change all the guids (including the one in product tag and all components) and configure as needed.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: