1
votes

1. Introduction

I've got an MSI installer build via the WIX toolset. This installer contains a dll library and a *.cab file that is used to install a 3rd party driver while installing my application. This process is done in the following steps: my MSI creates a directory in the INSTALLDIR, then the driver is installed there by executing a deferred custom action from mentioned dll. I think that this pattern isn't really a valid one, but that's a side note.

During an upgrade, the directory where MSI installed a driver is removed. This causes issues when it's time to upgrade the driver as it must be done via another custom action defined in the dll library and those removed files must be present. Please notice: I cannot uninstall and install the driver during an upgrade, it's a limitation, unfortunately.

2. Workaround

The RemoveExistingProduct was scheduled after InstallInitialize. As the driver's files mustn't be touched during an upgrade, as a workaround, I've changed RemoveExistingProduct to be executed after InstallExecute, so the files aren't firstly removed and then installed again, but rather overwritten if needed. I'm aware of how this affects the rollout procedures.

Question: Is this a proper/better way (as proper as a workaround can be...) of handling it? Can it cause some unwanted side-effects? So far I've observed in logs:

Disallowing uninstallation of component: {GUID-HERE} since another client exists

Another question: Is this expected?

3. Details and some XML

The Product ID and Package ID are always generated ("*"). The UpgradeCode remains the same between different versions. The REINSTALLMODE="omus". The upgrade is done via <Upgrade> element:

<Upgrade Id="$(var.UpgradeCode)">
  <UpgradeVersion OnlyDetect='no' Property='AUTO_FOUND_PREVIOUS'
    Maximum='$(var.VersionNumber)' IncludeMaximum='no'
    IgnoreRemoveFailure="yes" MigrateFeatures="yes" />

  <UpgradeVersion OnlyDetect='no' Property='AUTO_FOUND_SELF'
   Minimum='$(var.VersionNumber)' IncludeMinimum='yes'
   Maximum='$(var.VersionNumber)' IncludeMaximum='yes'
   IgnoreRemoveFailure="yes" MigrateFeatures="yes" />

  <UpgradeVersion OnlyDetect='yes' Property='AUTO_FOUND_NEWER'
   Minimum='$(var.VersionNumber)' IncludeMinimum='no' />
</Upgrade>

And as I mentioned, the directory where the driver is installed is also managed by my MSI:

<DirectoryRef Id='INSTALLDIR_DRIVER'>
    <Component Id='cmp_driverPlaceholderDir' Guid='{CONST-GUID-HERE}'>
        <CreateFolder />
        <RemoveFolder Id='INSTALLDIR_DRIVER' On='uninstall' />
    </Component>
</DirectoryRef>

Other components have also constant GUIDs.

I'd love to also hear how the installation of an external driver from custom action should be handled in the proper way, don't hesitate if you have some knowledge about it.

1
Do you already have a bootstrapper?Christopher Painter
Placing RemoveExistingProduct after InstallExecute (I'm assuming you are not using InstallExecuteAgain and there are no other actions between InstallExecute and InstallFinalize) is fine, as long as you are extremely rigorous in following the "Component Rules". I'd recommend never attempting Patching (minor upgrades and small updates are a can of worms you only wade into when absolutely necessary, and even then you should question yourself a few more times).B. Murri
Chances are the line in the logs you mention are coming from the removal of your previous version. The "another client" is the package you are just now installing.B. Murri
@B.Murri - yes, there are no other actions between InstallExecute and InstallFinalize, only RemoveExistingProduct. In case of minor upgrades and patches: I never do them, everything is deployed as a major upgrade. It's true that component rules must be followed.iksajotien

1 Answers

1
votes

At one time DIFX was the "authoritative method" for driver installations using MSI, but it has now been deprecated by Microsoft. The recommended replacement is called Setup API or Device and Driver Installation Reference (depending on much platform support you need) but each evolution is more difficult to use within the confines of Windows Installer (although I've been tempted several times to write a WiX extension wrapping those APIs to help all the driver writers out there) because of the need to maintain MSI's transactional guarantees whenever using deferred custom actions.

Current best practice (early 2021) is to use a bootstrapper that supports multiple packages & will securely cache your packages (so they are available during upgrades & uninstalls, etc.), and to have it install both your driver and your MSI.