WiX Checkbox property only working if default value given - wix

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.

Related

Wix Installer how do I create registry key if the user agrees to a dialog?

I am creating an installer in Wix.
I need a simple dialog during the installation where the user has to agree something, if they do, I want to create a registry key recording this choice.
This seems the simplest of tasks, but how do I use Wix to create the dialog and conditionally create the registry key based on the user's input?
So far I've tried to find out about custom actions, but it seems that this is not the right tool as Wix contains the ability to create a registry key already.
I just don't know how to tie installation of a feature to the response to a specific dialog.
If the agreement is not given, then the installer should continue as normal, just without this specific registry key.
I'm using Visual Studio.
Some code snippets:
This is at the top of my product, next to the other properties.
<Property Id="STREAMING_ACCEPTED" Secure="yes"/>
Then I have a dialog with the following control element.
<Control Id="StreamingAcceptedCheckBox" Type="CheckBox" X="20" Y="207" Width="330" Height="18" CheckBoxValue="1" Property="STREAMING_ACCEPTED" Text="Accept streaming" />
And finally, I'm trying to hook this up by adding a condition to the component.
<Component Id ="StreamingAcceptanceRegKey" Guid="some-guid" Win64="yes">
<Condition>STREAMING_ACCEPTED</Condition>
<RegistryKey Root="HKLM" Key="SOFTWARE\MyProgram" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Name="UsageStats" Value="true" Action="write" KeyPath="yes"/>
</RegistryKey>
</Component>
Am I on the right lines, because it's not writing the registry key? Does this actually record "true" and "false" to the property based on the checkbox state?
The UI control has a property associated with it. Make sure it's a secure custom public property. (All caps and marked secure ).
Describing how feature selection and INSTALLLEVEL works in an MSI takes some time. Since you only have 1 registry value I would instead suggest creating a component to set the registry value and putting a condition on that component that uses the secure custom public property found in the UI.
If you want to support the user going into Programs and Features and changing the original choice then make sure you mark the component as transitive and implement a WiX remember property pattern so that subsequent repairs / transactions keep the choice.
http://robmensching.com/blog/posts/2010/5/2/the-wix-toolsets-remember-property-pattern/

Condition inside Feature ignores property value that is set in custom action

I have a feature that I want to be selected or deselected according to a property value:
<Feature Id="featHAService" Title="!(loc.HAService)" AllowAdvertise="no" Level="1">
<Condition Level="3">
<![CDATA[PROP_IS_FIRST_INSTALLATION="0"]]>
</Condition>
</Feature>
In the C# custom action, before showing CustomizeSetup dialog that contains features tree, I set the PROP_IS_FIRST_INSTALLATION according to some logic and no matter if the value is 0 or 1 the Feature Level is always 1. For debug purposes I stopped triggering the custom action and manually changed the value of PROP_IS_FIRST_INSTALLATION int the *.wxs file, and condition works as expected. Any idea why changing it in custom action does not work?
Check the sequence order in which these calls happen, because the conditions in features are evaluated during the CostFinalize action, so your custom action must be before CostFinalize.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa368014(v=vs.85).aspx
It's more usual in my opinion to have a DoAction controlEvent in these cases. The dialog event can do an ADDLOCAL on the required feature and a remove on the other. The custom action can then be triggered by the feature condition on the feature being installed, such as &FeatureName=3. There is an example here:
How to set the list of features which will be installed if the button was pushed?

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.

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"