wix SetProperty After attribute won't take custom action Id - wix

After reading the page on SetProperty and looking at as many examples as I could find here and elsewhere, I'm still not able to get my SetProperty to work with After or Before set to one of my custom action IDs. The documentation seems very simple and straight forward on the subject (hah!), but I'm getting "Found an ActionRow with a non-existent After action: MyWonderfulCA" instead of happiness (which really is what I'm after : ) Here's a representation of what my code looks like:
<CustomAction Id="MyWonderfulCA" BinaryKey="MyWonderful.dll" DllEntry="MyWonderfulCA" Execute="immediate" />
<InstallExecuteSequence>
<Custom Action="MyWonderfulCA" After="LaunchConditions" />
</InstallExecuteSequence>
<Property Id="SOMEPROPERTY" />
<SetProperty Id="SOMEPROPERTY" After="MyWonderfulCA" Value="[SOMEOTHERPROPERTY]the\yellow\brick\road">WEAREHUNKYDORY</SetProperty>
So anyway, save me SOF wix pros, you're my only hope...

I'm not sure, but the following thing looks suspicious.
The <SetProperty> (link) element has Sequence attribute, which is optional. If you don't specify it (like in the sample you posted), it gets the value of both, which means the custom action of type 51 (which is what SetProperty translates to) is scheduled into both InstallUISequence and InstallExecuteSequence.
However, as far as I can see, you only schedule MyWonderfulCA into the InstallExecuteSequence. Hence, it makes me think that when WiX tries to schedule SetProperty into the InstallUISequence, it can't find the custom action specified in After attribute and fails.
Check this out by either specifying the Sequence='execute' explicitly, or by scheduling your wonderful CA into both sequence. If it is the case, then just choose the most appropriate way out of these two.

Related

How to register a COM dll on condition based in WIX Installer

Am running a Command to register a dll using the below code in WIX installer
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Impersonate='no' Execute='deferred'
ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]myProduct.dll" /codebase' Return='check' />
<CustomAction Id='comUnreg' Directory='INSTALLLOCATION' Impersonate='no' Execute='deferred' ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" /u "[INSTALLLOCATION]myProduct.dll" /codebase' Return='check' />
for registry entry and its working fine and my setup is also working cool. But now i need to register this in condition based (ie) in my installer i have given a checkbox ,if its checked then need to register the dll else no need to register.
I have used conditions for other uses by using <Condition>INSTALLADDIN</Condition> but its working only inside a <Component> </Component> but my command was inside <Product></Product> , how to set the condition for the above mentioned.??
and if i used as below
<Condition Message='EA-Addin not installed'>INSTALLADDIN</Condition>
above that code it shows that message and getting terminated.If i didnt set the message property it shows an error that message is a required property.How to overcome this problem.?
You need a condition on the custom action in your situation, I assume you've added it to the execute sequence somewhere but there's no condition on it.
Having said that, that's not really the way to do registration. Use Heat to extract it into a component with the Dll. You'd probably need need two components, one with the file+registration and one with just the file, make them mutually exclusive, and use the remember property pattern on the property. Condition the appropriate component on the condition.
There are conditions everywhere - it looks like you are confusing launch conditions (Condition Message...) with component conditions and custom action conditions.

Set default values in registry, if there are none

I am maintaining an old application in which the users configuration is stored in registry. It is left behind when uninstalling. I am now re-writing the installer in WiX.
The installer should add a default value in the registry if there are none there, otherwise
the existing value should be left alone.
I was thinking on how to do this in WiX. And the solution I came up with is somewhat cumbersome:
<Property Id="MY_PROPERTY">
<RegistrySearch Root="HKLM" Key="SOFTWARE\MyProduct" Name="MyProperty" Type="raw" />
</Property>
<CustomAction Id="ca.SetDefaultValue" Property="MY_PROPERTY" Value="DefaultValue" />
<InstallExecuteSequence>
<Custom After="RegistrySearch" Action="ca.SetDefaultValue">Not MY_PROPERTY</Custom>
</InstallExecuteSequence>
<Component Id="c.Registry">
<RegistryValue Root="HKLM" Key="SOFTWARE\MyProduct" Name="MyProperty" Type="string" Value="[MY_PROPERTY]" />
</Component>
So do a registry search to find old value. If not set, set to default value using a scheduled custom action. Then create the value "as usual".
Anyone who can think up a smoother way to do this?
Note that I cannot use convenient variables like Installed since values might be there, left behind by a previous, now uninstalled, version.
Start with the Wix Remember Property pattern but take it one step farther. After AppSearch runs and the REMEMBERME property does or doesn't get a value, use a SetProperty custom action to assign a default value if REMEMBERME="".
I take it one step farther though. I have a concept I call "property precedence". Basically it's a list of priorities for how a property should get it's value.
Highest to lowest:
properties inputted during the UI
public properties passed in at the command line
Properties found during AppSearch
Default values defined in the Property table
In other words, during a first time silent install with no properties passed at the command line the default value in the property table should be used.
During a second time silent install with no properties passed at the command line, the remembered value should take priority over the default value. (If different)
During a first of second silent install, a property passed at the command line should be considered an override value and take priority over both the default and remembered value.
During an interactive install the above rules take place and the UI should display that value. If the user changes the value then this is the ultimate value.
I'll leave it up to you of how to implement the various custom actions to do this. It generally involves a temp prop and a real prop and a series of Set Property CA's with the right execution scheduling and conditions to do what you want it to do.
You haven't explicitly set keypath=yes on the registry value in your component. However, in that case wix will select the first child item which can serve as the keypath. From the wix component element documentation:
If KeyPath is not set to 'yes' for the Component or for a child Registry value or File, WiX will look at the child elements under the Component in sequential order and try to automatically select one of them as a key path.
Therefore, your registry value is the keypath of the component which installs it. This means that the component will not be installed if the registry value already exists. As far as I can tell, that's the behavior you want.

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.

Set Wix property only if certain condition is met

What I would like to do is this:
<Property Id="LICENSEKEYPATH">
REMOVE~="ALL" AND NOT UPGRADINGPRODUCTCODE
<DirectorySearch Id="ProgramDataSearch" AssignToProperty="yes" Depth="4" Path="[#ProductDirInAppData]">
<FileSearch Id="LicenseFileSearch" Name="lic-conf.enp"/>
</DirectorySearch>
</Property>
When my application is being uninstalled, only then, do I want to search for the license file and get its path. Currently, although the code doesnt give any errors, it still searches for the license file path even when I am installing the file. Because of this, the setup gets delayed by a long time. And more importantly, the wix setup displays in the first screen to the effect that its searching for this property and then it continues with the other screens.
So, how do I search for a file or set the value of a property only during uninstallation?
You can control the setting of a property using the SetProperty element. That is just a shortcut for registering a custom action. You can control when the SetProperty executes using a Conditoin in the text element.
As for AppSearch (XxxSearch elements), you can add a condition like the one above to the AppSearch element so that it only runs during uninstall. Note that the conditioning the AppSearch element will affect all XxxSearch elements. So if you need to have a search working during install and another search only during uninstall, that is not possible.
PS: The condition you want will look something like:
Installed AND REMOVE="ALL"