WiX: CustomAction based on the outcome of another CustomAction

1.3k views Asked by At

I am fairly new to WiX so may be I am asking something very straight forward but I couldn't find much help googling it.

I want to perform 2 customActions, say, ca1 and ca2, where execution of ca2 depends on outcome of ca1, something like below:

if ( ca1 == SUCCESS )
{
  Perform ca2
}

So ca2 should only be executed if my ca1 returns success (doesnt fails).

What is the easiest way to do this in WiX ?

4

There are 4 answers

5
Michael Urman On BEST ANSWER

What you describe is the default. If a custom action fails, the installation aborts, and only rollback actions may execute afterward. So for your question to make sense, first you have to ignore or otherwise mask failures on your first custom action.

Second, the only way for one action to know the return result of another is if it invoked it by calling MsiDoAction (or some wrapper thereof). Doing that would blur the lines between your custom actions, so I'm going to assume that's not the scenario you're describing.

That leaves you with the third and final way: find an external communication channel. For immediate actions, I would suggest that ca1 sets a property upon success (call MsiSetProperty or a wrapper like DTF's session[property]), and ca2 either reads (MsiGetProperty / MsiEvaluateCondition) or is directly conditioned against the value of that property. For deferred actions, properties don't propagate, so you would have to identify some other channel. (Perhaps a temporary file whose path is chosen ahead of time would work.)

But the entire scenario is a little unusual for Windows Installer; I would recommend avoiding it. Perhaps merge your actions so that any failure scenarios can be handled "internally" before bubbling back to the sequence. Or perhaps the specifics of your actions might lead towards more specific suggestions.

0
Doc On

From the WiX documentation here

    <InstallExecuteSequence>
         <Custom Action='FooAction1' After='InstallFiles'/>
         <Custom Action='FooAction2' After='FooAction1' Condition='FOOACTION1SUCCESS'/>
    </InstallExecuteSequence>

Have your code in FooAction1 set the property MsiSetProperty('FOOACTION1SUCCESS', '1') Now FooAction2 will only run when FOOACTION1SUCCESS property is set. But really Michael Urman's response is correct. You should be handling the exception all within one custom action.

2
Stein Åsmul On

You must never make changes to the system using immediate mode custom actions. They will never run properly when the setup is executed by a restricted user with elevated rights (immediate mode actions never elevate, they always impersonate the user so anything you try to change will trigger access denied). Additionally they may fail to run in silent execution mode, depending on your sequencing (for example if you try to invoke them from your setup GUI).

Another "external communication channel" between custom actions that Michael Urman talks about might be a registry key in HKLM that you can write and then read back.

However, the real solution would be to try WiX's built-in firewall feature. It is written reliably by knowledgeable MSI-experts and supports proper rollback. It will be vastly superior to what anyone can roll on their own: http://wixtoolset.org/documentation/manual/v3/xsd/firewall/firewallexception.html

1
Doc On

Have the first custom action set a property. Then only run the 2nd custom action if that property exists or is set to the expected value.