How to pass CustomActionData to a CustomAction using WiX?
Deferred custom actions can not directly access installer properties (reference). In fact, only CustomActionData
property
session.CustomActionData
and other methods and properties listed here are available on the session object.
Therefore, for a deferred custom action to retrieve a property such as the INSTALLLOCATION
, you have to use a type 51 custom action — i.e. a set-property custom action — to pass that information along and you'll consume the data from the CustomAction's C# code through session.CustomActionData
. (see reference & reference)
Below is an example of a type 51 custom action (CustomAction1
) that will set a property that can be retrieved in CustomAction2
.
<CustomAction Id="CustomAction1"
Property="CustomAction2"
Value="SomeCustomActionDataKey=[INSTALLLOCATION]"
/>
Notice that Property
attribute name is CustomAction2
. This is important. The Property attribute's value of the type 51 action must be equal/identical to the name of the custom action that is consuming CustomActionData
. (see reference)
Notice the name SomeCustomActionDataKey
in the Value
attribute key/value pair? In your C# code in the consuming custom action (CustomAction2
), you'll look-up that property from CustomActionData
by using the following expression:
string somedata = session.CustomActionData["SomeCustomActionDataKey"];
The key that you use to retrieve the value from CustomActionData
is NOT the value in Property
attribute of the type 51 custom action, but the key from the key=value
pair in the Value
attribute. (Important takeaway: CustomActionData
is populated by setting an installer property that has the same name as the Id of the consuming custom action, but CustomActionData
keys are NOT installer properties.) (see reference)
In our scenario the consuming custom action is a deferred custom action defined somewhat like the below:
<Binary Id="SomeIdForYourBinary" SourceFile="SomePathToYourDll" />
<CustomAction Id="CustomAction2"
BinaryKey="SomeIdForYourBinary"
DllEntry="YourCustomActionMethodName"
Execute="deferred"
Return="check"
HideTarget="no"
/>
Configuring the InstallExecuteSequence
Of course, the consuming custom action (CustomAction2
) must run after the type 51 custom action (CustomAction1
). So you'll have to schedule them like this:
<InstallExecuteSequence>
<!--Schedule the execution of the custom actions in the install sequence.-->
<Custom Action="CustomAction1" Before="CustomAction2" />
<Custom Action="CustomAction2" After="[SomeInstallerAction]" />
</InstallExecuteSequence>
For us C++ schlubs, you retrieve the Property as follows:
MsiGetProperty(hInstall, "CustomActionData", buf, &buflen);
Then you parse 'buf'. Thank you to Bondbhai.