4
votes

I have a main application TheApp which supports plugins. Application A is installed by default at $(ProgramFiles)\TheApp, but the gold-owners want this to be user-customizable, so its location may vary depending on user input at installation time.

Plugins are installed by copying them to a subdirectory Packages under installation directory. Specifically, no registry settings need to be set for a package to load, and I'm trying to stay out of the registry as much as possible. Naturally, if the user changed the installation directory when installing TheApp, the plugins must also change their installation location to match.

How is this best accomplished? I'm not seasoned at writing MSI installers with WiX, but my first attempt would probably be to create a registry key when TheApp is installed saving its install location, and then have the plugins search for the registry key. This forces me to create registry value, which is what I'm trying to avoid if possible. However, it strikes me that the installer should be able to take advantage of the Windows Installer database to locate the TheApp's installation directory. That would remove the need for a registry entry.

Is there a "best practice" for how to do this inter-installer communication, specifically the installation directory? How would the communication look like, given that both installers will be written in WiX?

3

3 Answers

3
votes

Yes, you can use the Windows Installer database and, under certain conditions, without a custom action!

The standard tables and actions support searching for installed components. So, if your app directory has a certain component installed in it (e.g, your app .exe) that you give a fixed GUID, your plugin installer can find it.

Since you'll need the "MainComponentGuid" in all projects, extract it out as a define in an Include file.

Plugin authoring:

<?include ../MainSetup/MainComponentGuid.wxi?>

<Property Id="MAINDIR">
  <ComponentSearch Id="MainComponentSearch" Type="file" Guid="$(var.MainComponentGuid)">
    <DirectorySearch Id="MainComponentDirectorySearch" AssignToProperty="yes"  Depth="0" />
  </ComponentSearch>
</Property>

<CustomAction Id="SetInstallFolder" Directory="INSTALLFOLDER" Value="[MAINDIR]" />
<InstallExecuteSequence>
  <Custom Action="SetInstallFolder" After="CostFinalize">NOT Installed</Custom>
</InstallExecuteSequence>

In your Directory structure, you'd make Packages a child of INSTALLFOLDER. You might also use MAINDIR in a LaunchCondition to prevent installing a plugin unless the main product is installed.

1
votes

Writing a registry key during installation and then finding it is quite simple using WIX.

You can use the following to create a key:

<Component Id="RegistryEntries" Guid="PUT-GUID-HERE">
    <RegistryKey Root="HKCU"
                 Key="Software\MyApplicationName"
          Action="createAndRemoveOnUninstall">
     <RegistryValue Action="write"  Name="InstallDir" Type="string" Value="[INSTALLDIR]"  />
    </RegistryKey>
</Component>

Here InstallDir is a WIX property where the user selected target path of your software is set. Once you have this key setup then you can look for this in your plugins installer (assuming there is a separate installer for plugins) by using the following example:

<Property Id="AnyNameYouLike">
<RegistrySearch Id="YourRegistrySearchId"
                Root="HKCU"
                Key="Software\MyApplicationName"
                Name="InstallDir"
                Type="raw" />
</Property>

This code will set the value of property AnyNameYouLike to the path stored in InstallDir. You can put this code somewhere before you intend to use the path.

Alternatively, you can create a file in windows ProgramData\YourApp or in Users folder to store the install location if you really really want to avoid doing registry stuff.

0
votes

1) Check, if your main product writes InstallLocation key in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\

2) If there is no such key, set ARPINSTALLLOCATION property

3) If the key was written by main product - just read this value with RegistryLocator and set TARGETDIR.