Property does not exist or empty when accessed from deferred custom action
Problem
Property is created, but when deferred custom action tries to get its value - property either does not exist or its value is empty.
Sample
Let's test it with immediate custom action first to make sure that property has a value:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="{94A35E02-D48F-48F1-AC1A-23F62489BBF4}"
Name="Minimal Windows Installer Sample"
Language="1033"
Codepage="1252"
Version="1.0.0"
Manufacturer="Acme Corporation"
UpgradeCode="{74069BA4-1D1C-4252-A074-B2EC0C746403}">
<Package Id="{4C159FD5-135E-42DE-B36E-22DDDCBA3DCF}"
Description="Minimal Windows Installer Sample"
Comments="This installer database contains the logic and data required to install [ProductName]."
InstallerVersion="200"
Languages="1033"
SummaryCodepage="1252"
Platforms="Intel"
ReadOnly="no"
Compressed="yes"
AdminImage="no"
Keywords="Installer"
ShortNames ="no"
Manufacturer="Acme Corporation" />
<Media Id="1" Cabinet="CAB001.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">
<Component Id="Component1"
Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">
<File Id="ReadMe" DiskId="1" Name="Readme.txt" Source="Readme.txt" Vital="yes" KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Directory>
<Property Id="TESTPROPERTY" Value="Hello" />
<CustomAction Id="ShowProperty" Script="vbscript" Execute="deferred">
<![CDATA[
MsgBox Session.Property("TESTPROPERTY")
]]>
</CustomAction>
<InstallExecuteSequence>
<Custom Action="ShowProperty" Before="InstallFinalize">Not Installed</Custom>
</InstallExecuteSequence>
<Feature Id="Feature1"
Title="Feature1 title"
Description="Feature1 description"
Level="1"
ConfigurableDirectory="INSTALLDIR" >
<ComponentRef Id="Component1" />
</Feature>
</Product>
</Wix>
As you can see I explicitly set the value of the TESTPROPERTY property. Custom Action Type 38 shows the message box with the value of this property. Build MSI and test it.
Now, let's make our custom action ShowProperty deferred:
<CustomAction Id="ShowProperty" Script="vbscript"
Execute="deferred">
<![CDATA[
MsgBox Session.Property("TESTPROPERTY")
]]>
</CustomAction>
Let's test it again. As you can see, the message box is empty.
Why?
As you can see in this article on MSDN, deferred custom action can access only three property:
- ProductCode
- UserSID
- CustomActionData
Also, this article is saying that we need to add custom action to set the property with the same name as deferred custom action to the value of property we want to use in the deferred custom action. Defereed custom action must access CustomActionData property. Here is updated version:
<Property Id="TESTPROPERTY" Value="Hello" />
<CustomAction Id="ShowProperty" Script="vbscript" Execute="deferred">
<![CDATA[
MsgBox Session.Property("CustomActionData")
]]>
</CustomAction>
<CustomAction Id="SetPropertyForShowProperty"
Property="ShowProperty" Value="[TESTPROPERTY]" />
<InstallExecuteSequence>
<Custom Action="SetPropertyForShowProperty" Before="InstallInitialize">Not Installed</Custom>
<Custom Action="ShowProperty" Before="InstallFinalize">Not Installed</Custom>
</InstallExecuteSequence>
I've added new immediate Custom Action Type 51 to set the property with the name ShowProperty (same name as deferred custom action) and scheduled it in the InstallExecuteSequence table just before InstallInitialize standard action. Custom Action ShowProperty is using CustomActionData property now.
Build the MSI and make sure that it is working now.
What if I need more than one property?
If we need to access more than one property, we must pack them into CustomActionData. For example, if we know for sure that our properties will not have semi-colon in their value, we can concatenate property values and separate values using semi-colon. Here is an example:
<Property Id="TESTPROPERTY" Value="Hello" />
<Property Id="TESTPROPERTY2" Value="World" />
<CustomAction Id="ShowProperty" Script="vbscript" Execute="deferred">
<![CDATA[
Dim properties
properties = Split(Session.Property("CustomActionData"), ";", -1, 1)
MsgBox properties(0) & ", " & properties(1) & "!"
]]>
</CustomAction>
<CustomAction Id="SetPropertyForShowProperty"
Property="ShowProperty"
Value="[TESTPROPERTY];[TESTPROPERTY2]" />
<InstallExecuteSequence>
<Custom Action="SetPropertyForShowProperty" Before="InstallInitialize">Not Installed</Custom>
<Custom Action="ShowProperty" Before="InstallFinalize">Not Installed</Custom>
</InstallExecuteSequence>
Comments
Anonymous
April 26, 2009
Thanks a lot for this article. You are great. Regards Rakib HasanAnonymous
August 26, 2009
The comment has been removedAnonymous
August 26, 2009
I don't know what this GUID is. It might be something which is meaningful to this particular run of the installer and during next run this GUID for the same custom action could be completely different.Anonymous
November 29, 2009
What if I want to set a property value from a deferred custom actionAnonymous
January 23, 2010
Hi nice article, how to change value of property using custom action data ? Please reply to swapprakash@yahoo.co.in if you have solution for this. Thanks in advance.