Wednesday, 18 July 2012

WIX Registry Key Exists Custom Action

The RegistrySearch Element in WIX has a bug where by you cannot check the existence of a Key with out a value. ClickOnce installers with a custom bootstrapper manifest also inherits this issue as I believe that it is a problem in the underlying Windows Installer.
For a deployment component that I am currently building for an application I have a requirement to check if the .Net Platform Update 1 is installed as per the instructions here.

The key in question is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.0.1, which has no default value.

After taking a look around on the internet I could not find a code snippet that was flexible and reusable. Most where simple hard coded examples on how to work around the problem. So I decided to build my own Custom Action and add it to an assembly of custom actions that I share and reuse between deployment components.

The Custom Action

The code is pretty straight forward. A key name, as specified by the session property REGKEY, is opened from the registry hive as specified by REGHIVE session property. The session property REGKEYEXISTS is used to store the result of the check.

Using the Custom Action

To use the custom action in an installer first embed the custom action as a Binary Element.
< SourceFile="$(var.CustomActions.TargetDir)\Installer.CustomActions.CA.dll" CustomActions?>Then define the Custom Action and sequence it for execution, in this case it is before LaunchConditions.

<CustomAction Id="CheckRegistryKeyExists" BinaryKey="CustomActions" DllEntry="CheckRegistryKeyExists" Execute="immediate" Return="check" />
  <Custom Action="CheckRegistryKeyExists" Before="LaunchConditions">NOT Installed</Custom>

Then specify the required properties and setup the condition and message.
<Property Id="REGHIVE">HKLM</Property>
<Property Id="REGKEYEXISTS">0</Property>
<Condition Message='!(loc.Update401Missing)'>Installed OR REGKEYEXISTS="1"</Condition>

When the custom action is run with logging msiexec /i Workflow.Designer.Installer.msi /lv out.txt the following output is displayed to aid with debugging.

Action start 14:38:41: CheckRegistryKeyExists.
MSI (c) (A0:FC) [14:38:41:385]: Invoking remote custom action. DLL: C:\MSIA543.tmp, Entrypoint: CheckRegistryKeyExists
MSI (c) (A0:24) [14:38:41:387]: Cloaking enabled.
MSI (c) (A0:24) [14:38:41:387]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (A0:24) [14:38:41:387]: Connected to service for CA interface.
SFXCA: Extracting custom action to temporary directory: C:\MSIA543.tmp-\
SFXCA: Binding to CLR version v4.0.30319
Calling custom action Emex.Installer.CustomActions!Emex.Installer.CustomActions.CustomActions.CheckRegistryKeyExists
CheckRegistryKeyExists: Begin
CheckRegistryKeyExists: Looking up key SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.0.1 in Hive HKLM
MSI (c) (A0!F4) [14:39:09:498]: PROPERTY CHANGE: Modifying REGKEYEXISTS property. Its current value is '0'. Its new value: '1'.
CheckRegistryKeyExists: End


The statement Debugger.Launch() statement launches and attaches the debugger to the installer when the Custom Action is executed. In the above code it is surrounded with the #if DEBUG to prevent the debugger being launched in release mode.

When the debug version of the installer is launched the following dialog is displayed. You can attach the VS project that contains the source for the Custom Action and simply step through the code as you normally would.


No comments:

Post a Comment