I am working on an installer where I have to add a dialog for the user to make some application configuration choices. The dialog is shown before the installment procedure and the the configuration choices can only be applied after the installment when the required file are installed. The required file is some kind of configuration file which must be adapted based on the chosen configuration.
The sequence is as follows:
Start up the installer
Choose installation folder
Choose desired configuration
Install the application
Change the configuration based on the chosen desired configuration
The configuration dialog will have 2 components: one checkbox and one dropdownlist. Currently I am struggling with the checkbox and reading it's value in a deferred Custom Action. This Custom Action is executed after the installation is finished.
So far, this is the code I have:
<Dialog Id="TempDlgId" ...>
<Control Id="MyCheckBoxId" Type="CheckBox" ... CheckBoxValue="0" Property="MyCheckBoxValue" Text="Sampe Text"/>
</Dialog>
This is the dialog for the user to choose the configuration.
<Custom Action="MyCustomAction.SetProperties" After="InstallFiles">NOT Installed</Custom>
<Custom Action="MyCustomAction" After="MyCustomAction.SetProperties">NOT Installed</Custom>
I applied the sequencing for my custom actions.
<CustomAction Id="MyCustomAction.SetProperties"
Return="check"
Execute="immediate"
Property="MyCustomAction"
Value="InstallLocation=[DEFAULTWORKINGDIRECTORY];MyCheckBoxValue=[MyCheckBoxValue]"/>
<CustomAction Id="MyCustomAction"
Return="check"
Execute="deferred"
BinaryKey="MyCustomAction.CA.dll"
Impersonate="yes"
DllEntry="MyCustomAction"
HideTarget="no"/>
Here is my definition of the custom actions.
[STAThread]
[CustomAction]
public static ActionResult MyCustomAction(Session session)
{
Debugger.Launch();
var installLocation = session.CustomActionData["InstallLocation"];
var hasModule = session.CustomActionData["MyCheckBoxValue"];
return ActionResult.Success;
}
This code has to change the configuration of the installed application and currently I am struggling with getting the checkbox value. It doesn't matter if the checkbox is checked or not, MyCheckBoxValue is always empty. Is it possible to get the value of a checkbox in a deferred action? If it is possible, what do I have to do to get the checkbox value?
Since I am new to working on installers, I was not familiar with the fact that upper case actually has a functionality for creating installers with WiX. As soon as I wrote MyCheckBoxValue completely in uppercases, it became a public property and I managed to get it's value in the deferred Custom Action.
Related
As I understand it, in WiX, a checkbox is checked if the property is not null. So in order to default a checkbox to "Checked", the property must be defined apart from the checkbox.
Given that, I have a checkbox that allows the user to choose whether or not they want a shortcut added to their desktop. Originally it was set up to be checked by default, but I'm now trying to change it so that it is unchecked by default. However, when I remove the property definition so that it won't be checked, the option no longer works. The installer won't add the shortcut whether the checkbox is checked or not. Here's how the checkbox was originally defined:
<Property Id="ADD_DESKTOP_SHORTCUT" Value="1" />
<Control Id="ShortcutCheckbox"
Type="Checkbox"
Property="ADD_DESKTOP_SHORTCUT"
CheckBoxValue="1"
Integer="yes"
Text="Add Desktop Shortcut" />
The Desktop shortcut feature is defined as follows:
<Feature Id="DesktopShortcut" Title="Desktop Shortcut" Level="0">
<ComponentRef Id="CMP_DesktopShortcut" />
<Condition Level="1">
<![CDATA[(ADD_DESKTOP_SHORTCUT) or (REMOVE = "ALL")]]>
</Condition>
</Feature>
The above works, but as soon as I remove <Property Id="ADD_DESKTOP_SHORTCUT" Value="1" /> it no longer adds the shortcut regardless of the checkbox selection.
I've also tried leaving the property defined, but changing it's value like this:
<Property Id="ADD_DESKTOP_SHORTCUT" Value="{}" />
This doesn't work either. I get an error. (Error code 2892)
Can anyone tell me why removing the default value causes the option to stop working? And/or how to get it to work?
{} can't be used in the property table or the type 51 setproperty custom action. It only applies to a setproperty control event. You can have the property not set by simply declaring it and not giving it a value.
<Control Id="Custom" Type="CheckBox" X="20" Y="80" Width="320" Height="18" Property="MYPROPERTY" CheckBoxValue="Checked"/>
<Property Id="MYPROPERTY" Secure="yes"/>
If you go with a component condition, you should be aware that the component is installed if the condition is null or evaluates to true (not sure about that null thing, but that is what the SDK says).
I would suggest checking an actual value to avoid that null-trap:
<Property Id="ADD_DESKTOP_SHORTCUT" Secure="yes" Transitive="yes" />
<Component Id="CMP_DesktopShortcut">
<...>
<Condition>ADD_DESKTOP_SHORTCUT="1"</Condition>
</Component>
So that is ADD_DESKTOP_SHORTCUT="1" instead of just ADD_DESKTOP_SHORTCUT. You can obviously include Value="1" for the property element to make installing the shortcut default.
Note that I set Transitive="yes" to account for the fact that you might allow this setting to change in the setup's maintenance dialogs when it runs (not just the install dialogs), and then you can re-evaluate the component condition - potentially removing the component if the user changed the selection. (Transitive: "If this bit is set, the installer reevaluates the value of the statement in the Condition column upon a reinstall".)
I assume you install per-machine (ALLUSERS=1) and install the shortcut to the desktop shared by all users - to ensure all users can launch the application (otherwise you need to make further mechanisms to get the per-user shortcut added when you log in as another user).
A "Set Property Custom Action" (Type 51) can indeed undefine a property by setting its value equal to {} provided it runs prior to CostFinalize. I just tested this in the InstallExecuteSequence and it works fine.
Chris is probably talking about the setup GUI (dialogs show after the GUI version of CostFinalize has completed), in which case you should use the SetProperty ControlEvent instead of a SetProperty custom action - as he states (I didn't bother to test the SetProperty custom action here).
The below is no longer relevant since you seem to have abandoned the use of a conditioned feature, but with regards to your original question: "Can anyone tell me why removing the default value causes the option to stop working?"
Feature Condition: When you don't set the ADD_DESKTOP_SHORTCUT property at all, your feature condition is not true, and your feature will hence not switch from its default install level 0 (don't install) to install level 1 (install):
<Feature Id="DesktopShortcut" Title="Desktop Shortcut" Level="0">
<Condition Level="1">
<![CDATA[(ADD_DESKTOP_SHORTCUT) or (REMOVE = "ALL")]]> <= True only on uninstall
</Condition>
</Feature>
Feature Condition Problem: Note that any feature set to Level=0 as default will not be extracted during an administrative install at all (!), regardless of any feature conditions setting the feature to install. This is quite mad to be honest, but seems to be how admin installs currently work. I can not see any benefits to this design.
You can avoid setting any features to Level=0 by setting Level=1 as default and then set them to Level=0 with a feature condition that evaluates to true. This way the feature may be hidden in a regular installation, but all features - with associated files - are extracted during admin installation.
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.
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.
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.
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.