Partilhar via


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:

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 Hasan

  • Anonymous
    August 26, 2009
    The comment has been removed

  • Anonymous
    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 action

  • Anonymous
    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.