29
votes

How can I make a major upgrade to an installation set (MSI) built with WiX install into the same folder as the original installation?

The installation is correctly detected as an upgrade, but the directory selection screen is still shown and with the default value (not necessarily the current installation folder).

Do I have to do manual work like saving the installation folder in a registry key upon first installing and then read this key upon upgrade? If so, is there any example?

Or is there some easier way to achieve this in MSI or WiX?

As reference, I my current WiX file is below:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
    <Product Id="a2298d1d-ba60-4c4d-92e3-a77413f54a53"
             Name="MyCompany Integration Framework 1.0.0"
             Language="1033"
             Version="1.0.0"
             Manufacturer="MyCompany"
             UpgradeCode="9071eacc-9b5a-48e3-bb90-8064d2b2c45d">

        <!-- Package information -->
        <Package Keywords="Installer"
                 Id="e85e6190-1cd4-49f5-8924-9da5fcb8aee8"
                 Description="Installs MyCompany Integration Framework 1.0.0"
                 Comments="Installs MyCompany Integration Framework 1.0.0"
                 InstallerVersion="100"
                 Compressed="yes" />

        <Upgrade Id='9071eacc-9b5a-48e3-bb90-8064d2b2c45d'>
            <UpgradeVersion Property="PATCHFOUND"
                            OnlyDetect="no"
                            Minimum="0.0.1"
                            IncludeMinimum="yes"
                            Maximum="1.0.0"
                            IncludeMaximum="yes"/>
        </Upgrade>

        <!-- Useless but necessary... -->
        <Media Id="1" Cabinet="MyCompany.cab" EmbedCab="yes" />

        <!-- Precondition: .NET 2 must be installed -->
        <Condition Message='This setup requires the .NET Framework 2 or higher.'>
            <![CDATA[MsiNetAssemblySupport >= "2.0.50727"]]>
        </Condition>

        <Directory Id="TARGETDIR"
                   Name="SourceDir">
            <Directory Id="MyCompany"
                       Name="MyCompany">
                <Directory Id="INSTALLDIR"
                           Name="Integrat"
                           LongName="MyCompany Integration Framework">
                    <Component Id="MyCompanyDllComponent"
                               Guid="4f362043-03a0-472d-a84f-896522ce7d2b"
                               DiskId="1">
                        <File Id="MyCompanyIntegrationDll"
                              Name="IbIntegr.dll"
                              src="..\Build\MyCompany.Integration.dll"
                              Vital="yes"
                              LongName="MyCompany.Integration.dll" />
                        <File Id="MyCompanyServiceModelDll"
                              Name="IbSerMod.dll"
                              src="..\Build\MyCompany.ServiceModel.dll"
                              Vital="yes"
                              LongName="MyCompany.ServiceModel.dll" />
                    </Component>

                    <!-- More components -->
                </Directory>
            </Directory>
        </Directory>

        <Feature Id="MyCompanyProductFeature"
                 Title='MyCompany Integration Framework'
                 Description='The complete package'
                 Display='expand'
                 Level="1"
                 InstallDefault='local'
                 ConfigurableDirectory="INSTALLDIR">
            <ComponentRef Id="MyCompanyDllComponent" />
        </Feature>

        <!-- Task scheduler application. It has to be used as a property -->
        <Property Id="finaltaskexe"
                  Value="MyCompany.Integration.Host.exe" />
        <Property Id="WIXUI_INSTALLDIR"
                  Value="INSTALLDIR" />

        <InstallExecuteSequence>
            <!-- command must be executed: MyCompany.Integration.Host.exe /INITIALCONFIG parameters.xml -->
            <Custom Action='PropertyAssign'
                    After='InstallFinalize'>NOT Installed AND NOT PATCHFOUND</Custom>
            <Custom Action='LaunchFile'
                    After='InstallFinalize'>NOT Installed AND NOT PATCHFOUND</Custom>

            <RemoveExistingProducts Before='CostInitialize' />
        </InstallExecuteSequence>

        <!-- execute comand -->
        <CustomAction Id='PropertyAssign'
                      Property='PathProperty'
            Value='[INSTALLDIR][finaltaskexe]' />
        <CustomAction Id='LaunchFile'
                      Property='PathProperty'
                      ExeCommand='/INITIALCONFIG "[INSTALLDIR]parameters.xml"'
                      Return='asyncNoWait' />

        <!-- User interface information -->
        <UIRef Id="WixUI_InstallDir" />
        <UIRef Id="WixUI_ErrorProgressText" />
    </Product>
</Wix>
3

3 Answers

34
votes

There's an example in the WiX tutorial: https://www.firegiant.com/wix/tutorial/getting-started/where-to-install/

<Property Id="INSTALLDIR">
  <RegistrySearch Id='AcmeFoobarRegistry' Type='raw'
    Root='HKLM' Key='Software\Acme\Foobar 1.0' Name='InstallDir' />
</Property>

Of course, you've got to set the registry key as part of the install too. Stick this inside a component that's part of the original install:

<RegistryKey
         Key="Software\Software\Acme\Foobar 1.0"
         Root="HKLM">
  <RegistryValue Id="FoobarRegInstallDir"
             Type="string"
             Name="InstallDir"
             Value="[INSTALLDIR]" />
</RegistryKey> 
5
votes

'Registry' is deprecated. Now that part of code should look like this:

<RegistryKey Id="FoobarRegRoot"
             Action="createAndRemoveOnUninstall"
             Key="Software\Software\Acme\Foobar 1.0"
             Root="HKLM">
  <RegistryValue Id="FoobarRegInstallDir"
                 Type="string"
                 Name="InstallDir"
                 Value="[INSTALLDIR]" />
</RegistryKey>
4
votes

You don't really need to separate RegistryKey from RegistryValue in a simple case like this. Also, using HKMU instead of HKLM takes care of it whether you're doing a machine or user install.

<RegistryValue
  Root="HKMU"
  Key="Software\[Manufacturer]\[ProductName]"
  Name="InstallDir"
  Type="string"
  Value="[INSTALLDIR]"
  KeyPath="yes" />