17

I'm trying to create a custom action with "Value" attribute, I want to pass parameters to the C# code (the TARGETDIR and the version).

However, I get an error stating that DLLENtry and Value cannot coexist. But the custom action without dllentry is invalid.

This is the code:

 <CustomAction Id="SetMAWPrefferences"
                Value="InstallDir=[TARGETDIR];Version=2.0.0.1"
                Return="check"
                Execute="commit"
                BinaryKey="ImportExportBinary"                    
                />

And for it I get this error:

Error 9 ICE68: Invalid custom action type for action 'SetMAWPrefferences'.

Any ideas how to do it?

Yurii
  • 4,811
  • 7
  • 32
  • 41
Ehud Grand
  • 3,501
  • 4
  • 33
  • 52

2 Answers2

44

There are two ways to pass parameters to the custom actions, one will work for the immediate execution CA and the other one will work for the deferred custom actions.

Immediate CA (Can't be rolled back):

In order to pass arguments to the immediate CA you can set a property with the required name and access it from your session.

In Wix:

<Property Id="MyProp" Value="MyValue" />

In CA:

[CustomAction]
public static ActionResult NameOfMyCA(Session session)
{
    string myArg = session["MyProp"];
}   

Deferred CA:

In order to pass arguments to the deferred CA you need to use the CustomActionData Property, this property is the only one you can access from a deferred CA.

In the case of WIX, the DTF includes a CustomActionData class which is a key/value dictionary, and you can access it using:

In Wix:

<CustomAction Id="MyCustomAction" .../>

<Property Id="MyCustomAction" Value="Arg1=value1;Arg2=value2;Arg3=value3;Arg4=[MyProperty]" />

In CA:

[CustomAction]
public static ActionResult NameOfMyCA(Session session)
{
    CustomActionData data = session.CustomActionData;

    //Access each argument like this:

    string arg1 = data["Arg1"];
    string arg2 = data["Arg2"];
    string arg3 = data["Arg3"];
}    

Immediate CA + CustomActionData:

If you want to use the CustomActionData for your Immediate CA you can do something like this:

In Wix:

<Property Id="MyCustomAction" Value="Arg1=value1;Arg2=value2;Arg3=value3;Arg4=[MyProperty]" />

In CA:

[CustomAction]
public static ActionResult NameOfMyCA(Session session)
{
    CustomActionData data = new CustomActionData(session["MyCustomAction"]);

    //Access each argument like this:

    string arg1 = data["Arg1"];
    string arg2 = data["Arg2"];
    string arg3 = data["Arg3"];
    string arg4 = session.Format(data["Arg4"]);
}

In the case of Arg4 since it contains the value of a property you will need to access it like this:

string arg4 = session.Format(data["Arg4"]);

Unfortunately this will work in immediate CA only, this means that if you want to use the value of this property in a deferred CA you will need to have two custom actions:

  • CA 1 to set the CustomActionData for the CA executed as immediate. (Remember to name the property with the same name defined for your CustomAction.

  • CA 2 the CA with the specific logic that consumes CustomActionData.

I suggest you to use the CustomActionData for all the cases, this way is easier to convert you CA from Immediate to Deferred and the code is easier to read.

References:

session.Format CustomActionData

Rolo
  • 3,208
  • 1
  • 24
  • 25
9

Note, you're using Value attribute in the wrong way:

...this attribute must be used with the Property attribute to set the property...Source


Based on the Creating WiX Custom Actions in C# and Passing Parameters article you should:

  1. Create properties with desired values:

    <Property Id="InstallDir" Value="someDefaultValue" />
    <Property Id="Version" Value="2.0.0.1" />
    
  2. Create custom action to set the InstallDir property:

    <CustomAction Id="SetDirProp" Property="InstallDir" Value="[TARGETDIR]" />
    
  3. Create custom action:

    <CustomAction Id="SetMAWPrefferences" 
        Return="check" 
        Execute="commit" 
        BinaryKey="ImportExportBinary" 
        DllEntry="YourCustomAction" />
    
  4. Schedule custom actions for execution during installation process:

    <InstallExecuteSequence>
        <Custom Action="SetDirProp" After="CostFinalize" />
        <Custom Action="SetMAWPreferences" ... />
        ...
    </InstallExecuteSequence>
    
  5. Access those properties from your custom action as follows:

    [CustomAction]
    public static ActionResult YourCustomAction(Session session)
    {
        // session["InstallDir"]
        // session["Version"]
    }
    
Hakan Yildizhan
  • 172
  • 1
  • 9
Yurii
  • 4,811
  • 7
  • 32
  • 41
  • Hi the values are not passing - I'm getting null. – Ehud Grand Nov 24 '14 at 10:28
  • Thank you, the values are passing! however, I get [TARGETDIR] as a string, and google isn't helpful - I need the path, not the name of the property. – Ehud Grand Nov 24 '14 at 12:44
  • @user1223457, I've updated the answer yet again, hope it helps. – Yurii Nov 24 '14 at 13:32
  • No, I'm still getting just a string "TARGETDIR" – Ehud Grand Nov 24 '14 at 14:02
  • @user1223457, try changing `Value="[TARGETDIR]"` to `Value="[INSTALLFOLDER]"` in the ` – Yurii Nov 24 '14 at 14:04
  • Mo, not helping, still getting just a string. I do thank you for all your help! Perhaps there is another way? – Ehud Grand Nov 24 '14 at 15:47
  • 1
    `Execute="commit"`........... no. `Commit` CAs are executed after `InstallFinalize`, and only if rollback is enabled. If you're setting properties, they need to be done in `immediate` CAs, if you're changing the target system, they need to be done in `deferred` CAs. `Commit` CAs are for cleaning up temp files after successful install. – Izzy Oct 25 '16 at 10:00
  • Sadly, they removed/disabled the MSDN blog. It was really helpful. – ArNumb Jan 29 '19 at 09:06