WIX: How can I queue custom action between "after InstallFile" and "before "XMLFile" ? - wix

I have a custom action that dynamically generates an XML file based on installed files (can't change this utility). The custom action must execute after "InstallFiles".
I would like to use XMLFile to make other modifications to the XML file based on other features installed.
Any suggestions on how to schedule custom action between "after=InstallFile" and "before "XMLFile" ?

You can do something like
<Custom action="CustomizingXMLData" after="InstallFiles">Condition</Custom>
<Custom action="XMLFile" after="CustomizingXMLData">Condition</Custom>

Related

Wix - schedule custom action between StopServices and StartServices

I would like to add a custom action in my Wix installer that runs between the StopServices and the StartServices. So that the service is down when the custom action is running. If I do the following the action runs before the StartServices, but also before the StopServices.
<Custom Action="IisRewriteRules" After="StopServices" Before="StartServices"> NOT REMOVE~="ALL" </Custom>
It seems that I can't add both a Before and After tag, that gives following error:
Error CNDL0035: The Custom/#After attribute cannot be specified when attribute Before is present. (20)
Is there some way I can achieve this? As a backup I guess I could stop the service in my custom action and restart it again at the end of the custom action, but I would prefer to not have to do that.
Looking online I couldn't really find anything. Is there maybe a way to schedule the ServiceControl?
I found in the Wix Docs that you can add a Sequence tag instead of Before or After. You can pass this an integer value and schedule it between the default actions. Following page shows the default actions and their corresponding Sequence value: Suggested InstallExecuteSequence

Get target file path from custom action

How can I get a path to file being installed from a WiX custom action?
I'm creating a WIX Extension, which has a custom element which can be nested under <File> component like this:
<Component Id="FooComponent">
<File Id="filekey" Name="foo.txt">
<myextension:Stuff />
</File>
</Component>
The extension has its custom table which has a foreign key columns pointing to "Component" and "File" tables, and it is executed when a file's component is being installed/uninstalled (like the built-in IIS extension or SQL extension for example)
What I want to achieve is, in my deferred (sheduled) custom action, figure out the target path of the file the extension isbound to. I.e. basically in the differed custom action, I want to get value of [!filekey] (in terms of MSI formatted string). How can I go about that?
I have found a somewhat similar topic here
One of the solutions suggested was to use MsiFormatRecord from a custom action and pass that [#filekey] to that function. It resolves properly then.
I've found examples of using this approach in WiX sources, in gaming extension and NetFX extensions; they use code like this:
StrAllocFormatted(&pwzFormattedFile, L"[#%s]", pwzFileId);
WcaGetFormattedString(pwzFormattedFile, &pwzGamePath);
Here WcaGetFormattedString is basically a wrapper for MsiFormatRecord
Still unanswered, is this a right approach to the issue?
Basically you pass that [!filekey] to the deferred custom action in that format, using the CustomActionData indirect way of doing that. Then in your custom action you get the property value [CustomActionData] . This might help:
How to pass CustomActionData to a CustomAction using WiX?
To spell it out, if your type 51 custom action that is used to prepare CustomActionData has a Target of [!filekey] then when you retrieve the value of the CustomActionData property inside your custom action then it will contain the full path to the file, the entire path and filename. This demonstrably works, although it wouldn't be practical if you were doing this for many files.

WIX Custom Actions sequence

I have defined a few Custom Actions in my WIX setup, and these actions call third party EXE's that our application depends on. The user decides to install or ignore these 3rd party applications from the feature tree. My CustomAction and binary tags look like this:
<CustomAction Id='NL220_Action' BinaryKey='NL220EXE' Return='asyncWait' />
<Binary Id="NICEXE" SourceFile="..\NL220.exe" />
<CustomAction Id='NIC_Action' BinaryKey='NICEXE' Return='asyncWait' />
<Binary Id="NICEXE" SourceFile="..\NIC.exe" />
Furthermore, my InstallExecuteSequence tag looks like this:
<InstallExecuteSequence>
<Custom Action="NL220_Action" After="InstallFinalize"><![CDATA[(&Optional_NL220=3)]]></Custom>
<Custom Action="NIC_Action" After="NL220_Action"><![CDATA[(&Optional_NIC=3)]]></Custom>
</InstallExecuteSequence>
Everything works fine: the user can select which 3rd party installer packages to run, and these are then run when the installer finishes. The problem is that if the user selects both 3rd party installers, they are run at the same time, thus ignoring the After="NL220_Action" attribute of the second custom action. Any ideas why this is?
Per Custom Action Return Processing Options, the wait of asyncWait occurs at the end of a sequence. Use of this value means that you need the action to succeed, but you don't care exactly when it succeeds. If it waited for the custom action to finish before continuing onward, it would be synchronous. If you need to wait for the first to complete before running the second, then either you need to make the first action synchronous, or possibly combine both actions into a single asynchronous action which itself runs the two sub-actions in ordered sequence.

How can I disable a Wix component when a Feature is selected?

It's easy in Wix to enable a component when a feature is selected. I want to do the opposite of that, where the component will be installed unless a given feature is selected. The reason is that the component performs a configuration change that is not required if the given feature is chosen.
Failed Experiments:
I've tried using conditions in the component:
<Component ...>
<Condition>&Feature = 3</Condition>
...
</Component>
That doesn't work, because apparently the feature states are not calculated at the point where the component conditions are evaluated.
I've also tried using a custom action set to run before CostFinalize in order to set a property that can be tested in the Component condition. This also didn't work:
<Custom Action="Transfer_Feature_State" Before="CostFinalize" />
<Custom Action="Transfer_Feature_State_Property" Before="MtpWeb_Features_LabManager" />
<Custom Action="Transfer_Feature_State_Feature" Before="MtpWeb_Features_LabManager" />
When the custom action ran, the feature state was still set as -1, so the feature states have not been calculated before CostFinalize.
Is there any way to disable a component based on feature selection?
Components are organized into features. This means that by default all components in a feature are installed. If you don't want a feature to install a component, you can make sure that the component is not included in that feature.
What you really want is mutually exclusive features. Basically a feature which contains the component can be installed only if the other feature is not installed and the other way around.
This is not supported by Windows Installer, so it can be done only with a custom action. Basically, when the given feature is selected you can use MsiSetFeatureState function to make sure that the other feature which contains your component is not installed.

uninstall custom actions

After which custom action should my C# custom actions execute? And what condition should I use so my custom action could run only on uninstall?
After which custom action should my C#
custom actions execute?
It depends on what they do.
And what condition should I use so my
custom action could run only on
uninstall?
REMOVE = "ALL"
You need to provide the condition in custom action call as to when they should be called.
Example :
<Custom Action="UpdateConfig" After="InstallFinalize">INSTALL_APPLICATION = "1"</Custom>
Here, as you can see the custom action UpdateConfig will be called after everything is installed and if Application was selected as feature while installing.