WiX Burn - Determine what items are already installed
Asked Answered
E

2

8

I've a burn installation whereby the user can select which of three options to install - each one directly relates to one of three MsiPackages in a chain, such as :

<Chain>
  <MsiPackage SourceFile="..\ProductA\bin\Release\ProductA.msi"  InstallCondition="chkProductA" />
  <MsiPackage SourceFile="..\ProductB\bin\Release\ProductB.msi"  InstallCondition="chkProductA" />
  <MsiPackage SourceFile="..\ProductC\bin\Release\ProductC.msi"  InstallCondition="chkProductC" />
</Chain>

All fine. However, when I run the msi next time, I only want to re-install/update the items that were selected originally - ie if only productA was selected, I don't want to install products B & C.

How do I determine what was originally selected?

East answered 16/10, 2012 at 14:41 Comment(0)
E
10

OK, Sorted it, so I'd best post my solution.

Ultimately it boils down to two parts...

a) setting a registry key in each of the Product MSI's which are set on installation. Obviously if that MSI was not installed originally, then the registry entry will not exist. i.e.

  <!-- registry entry to state that the item has been installed-->
  <Component Id="cmp_WriteToRegistry" Guid="[yourguid]">
    <RegistryKey Root="HKLM"
                 Key="Software\MyCompany]"
          Action="createAndRemoveOnUninstall">
      <RegistryValue Type="integer" Name="ProductA" Value="1" KeyPath="yes"/>
    </RegistryKey>
  </Component>

b) Checking for the existence of that registry key in burn when doing the upgrade...

<!-- Determine what items are to be installed in the event of an install using the BA-->
<WixVariable Id="chkProductA" Value="![CDATA[chkProductA]]" />
<WixVariable Id="chkProductB" Value="![CDATA[chkProductB]]" />
<WixVariable Id="chkProductC" Value="![CDATA[chkProductC]]" />

<!-- Determine what items are installed in the event of an upgrade-->
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\MyCompany" Value="ProductAInstalled" Variable="ProductAInstalled" Result="exists" />
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\MyCompany" Value="ProductBInstalled" Variable="ProductBInstalled" Result="exists" />
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\MyCompany" Value="ProductCInstalled" Variable="ProductCInstalled" Result="exists" />

<Chain>
  <MsiPackage SourceFile="..\SetupProductA\bin\Release\SetupProductA.msi"
              InstallCondition="chkProductA OR ProductAInstalled" />
  <MsiPackage SourceFile="..\SetupProductB\bin\Release\SetupProductB.msi"
              InstallCondition="(chkProductB) OR (ProductBInstalled)" />
  <MsiPackage SourceFile="..\SetupProductC\bin\Release\SetupProductC.msi"
              InstallCondition="(chkProductC) OR (ProductCInstalled)" />
</Chain>

</Bundle>

So in the InstallCondition, chkProductA evaluates to true when the UI is used and the respective checkbox is checked, and ProductAInstalled evaluates to true when the respective product has already been installed - taking care of the update which in my case happens without any user interaction.

Easy when you know how. I certainly didn't to start with...

East answered 19/10, 2012 at 13:38 Comment(3)
The old etiquette of answering your own question thing again... If anyone has a better answer I would be really pleased to hear it, as though the above is AN answer, it may not be the BEST. If there are no better answers in a week or so I'll set this as the answer. I'm not fishing for points so guess this is the correct thing to do...East
Your solution is how I would do it. It is similar to the "Remember Property Pattern": robmensching.com/blog/posts/2010/5/2/…Chrystal
Thanks Bryan. I'm still at the beginner / re-inventing the wheel stage, so it's good to know.East
A
3

If you are doing your own managed bootstrapper application, you can do this in a DetectPackageComplete event handler:

CustomBA_DetectPackageComplete(object sender, DetectPackageCompleteEventArgs e)
{
    if (e.PackageId == "SetupProductA" && e.State == PackageState.Present)
    {
        CustomBA.Engine.NumericVariables["chkProductA"] = 1;
    }
    etc...
}

A similar thing can be done to detect installed features using DetectMsiFeature.

That being said, I would only use this method if you already have a custom BA. Building a custom BA is a lot of work.

Animation answered 30/8, 2013 at 17:4 Comment(2)
are you suggesting to do the registry search in the custom managed boostraper application too?Mycobacterium
@phoenix, you don't need to do a registry search assuming you are including an updated version of the msi in your bundle. The burn engine will detect the existing msi based on the related msi's upgrade code in your bundle and fire the 'DetectPackageComplete' event. John Wright has written up a nice example of handling this.Animation

© 2022 - 2024 — McMap. All rights reserved.