0

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 ?

foobar
  • 2,887
  • 2
  • 30
  • 55

4 Answers4

5

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.

Michael Urman
  • 15,737
  • 2
  • 28
  • 44
  • Thanks for answering. Thing is that I dont want to abort and rollback the installation if ca1 fails, just that ca2 doesnt executes on ca1 failure. Both ca1 and ca2 actions are immediate so I think using the 3rd way is the way. So how do I set a property based on ca1 result .. any sample code ? – foobar Aug 28 '17 at 13:00
  • To be specific, in ca1 I want to check if the windows firewall service is enabled, and in ca2 I will add my application as exception in the firewall exception list. – foobar Aug 28 '17 at 13:03
  • Would a HKLM key written by one CA be readable by the second CA? Even in deferred mode? I have never used such a constructs. Seems a little "deployment smelly" to me. In either case I think he should try WiX's firewall features? – Stein Åsmul Aug 29 '17 at 13:28
  • Thanks, I have considered handling both action in one call only. – foobar Aug 29 '17 at 17:46
  • @SteinÅsmul while I don't see any reason it wouldn't work for elevated actions, I would suggest avoiding it. I'm influenced by the admonition against using the registry for inter-process data sharing in the [desktop bridge docs](https://learn.microsoft.com/en-us/windows/uwp/porting/desktop-to-uwp-prepare). Sure, this case isn't exactly inter-process, but it's still another misuse of the registry. (You're probably correct about the firewall features, or a set it up without regard to initial state. But that's based on comments; the Q&A remains somewhat more general.) – Michael Urman Aug 30 '17 at 02:36
2

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

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • Thanks a lot for your inputs.There is already a Firewall DLL written in C++ that is being used in the project, so I am not entitled to change it. But I hope your answer will help someone else. – foobar Aug 29 '17 at 17:48
  • 1
    OK, as stated - be sure to not run the custom action(s) in immediate mode - or you will see problems for corporate deployment where restricted users install with elevated rights. And don't insert the custom action(s) in the setup GUI only (InstallUISequence) - this sequence is skipped entirely when your setup is installed silently. You should use deferred custom action(s) inserted into the InstallExecuteSequence. I can provide some details on how to test that this works if you like in a separate answer. – Stein Åsmul Aug 29 '17 at 19:15
1

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.

Doc
  • 698
  • 3
  • 16
0

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.

Doc
  • 698
  • 3
  • 16
  • Thanks, but can you show some sample/reference code about how to set a property using a custom action. – foobar Aug 29 '17 at 05:40