WiX installer - Read from registry to checkbox value - wix

I am fairly new to WiX and I got an issue where I cannot read a value from the registry to a Checkbox. I can read and populate to a ComboBox properly from the registry but for some reason the checkbox is not working.
Here is a part of my CustomUI.wxs
<Property Id="HEAPSIZEVALUE" Value="-Xms1024m" Secure="yes">
<RegistrySearch Id="RegHeapSizeValue" Type="raw" Root="HKCU"
Key="Software\Altair Semiconductor\!(loc.ProductName)" Name="Heap_Size" />
</Property>
<Property Id="POWERMODE" Value="1" Secure="yes">
<RegistrySearch Id="RegPowerModeValue" Type="raw" Root="HKCU"
Key="Software\Altair Semiconductor\!(loc.ProductName)" Name="Power" />
</Property>
<SetProperty Id="POWERMODE" Value="0" Before="InstallInitialize" Sequence="execute">NOT POWERMODE</SetProperty>
<UI Id="WixUI_MyMondo">
<Dialog Id="UserOptionsDialog" Width="370" Height="270" Title="Dialog Title">
<Control Id="TextLine2" Type="Text" X="50" Y="30" Width="250" Height="55" Text="Please choose the values for each of the following options (This can be skipped if typical options suffice)" TabSkip="yes" Transparent="yes" />
<Control Id="heapSizeLabel" Type="Text" X="50" Y="80" Height="17" Width="55" Transparent="yes" Text="Heap Size:" />
<Control Id="ComboBoxMain" Type="ComboBox" X="100" Y="79" Width="150" Height="20" Property="HEAPSIZEVALUE" >
<ComboBox Property="HEAPSIZEVALUE">
<ListItem Value="-Xms1024m" />
<ListItem Value="-Xms2048m" />
<ListItem Value="-Xms4096m" />
</ComboBox>
</Control>
<Control Id="PowerMode" Type="CheckBox" X="50" Y="100"
Width="290" Height="17" Property="POWERMODE"
CheckBoxValue="[POWERMODE]"
Text="Power (Allow device to sleep)" />
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next" />
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="Back" />
</Dialog>
Here is my registry
My installer
As you can see my Heap_size field is read properly from the registry and shown to the user but for some reason the checbox is always shown as selected.
I went through the logs also and I see that the value is read properly from the registry
MSI (c) (08:24) [11:28:01:194]: PROPERTY CHANGE: Modifying POWERMODE property. Its current value is '1'. Its new value: '0'.

In Windows Installer, the CheckBoxValue field is the value of the property when the checkbox is selected not the property itself. When it's not selected it's null. So change it to CheckBoxValue="1".
Where it says Property="POWERMODE" this is the property that will control the checkbox. If it matches the value of CheckBoxValue then it'll be checked. If it's null it won't.
There is a wierd UI bug (feature?) in MSI that if you don't give CheckBoxValue a value then the control can't be checked and unchecked.
https://learn.microsoft.com/en-us/windows/win32/msi/checkbox-table
Remarks
If the check box is selected, then the corresponding property is set
to the specified value. If there is no value specified or this table
does not exist, then the property is set to its original value when
the check box is selected. If the original value is null, the property
is set to "1".
By the above logic an unspecified value causes the uncheck to set the property to 1 which then gets interpreted as checked causing the deadlock.

Related

WIX Custom Action Condition using Property Value not working

I am trying to run a custom action at the end of my Wix installer but only if certain conditions are met. The user runs through the installer and they will choose one of two modes that set the property 'ServiceType'. The two values for the property are "RegisterNew" and "LinkExisting". You can see by the log below that when the user selects "LinkExisting" in the UI that it changes the property but the custom action still runs.
MSI (c) (D4:44) [11:20:15:686]: PROPERTY CHANGE: Modifying ServiceType property. Its current value is 'RegisterNew'. Its new value: 'LinkExisting'.
Here is my custom action code:
<InstallExecuteSequence>
<Custom Action="RegisterServiceNameCustomAction" Before="InstallFinalize">
<![CDATA[(ServiceType="RegisterNew") AND (NOT Installed)]]>
</Custom>
</InstallExecuteSequence>
<Fragment>
<Binary Id="RegisterServiceCustomActionBinary" SourceFile="$(var.RegisterServiceCustomAction.TargetDir)$(var.RegisterServiceCustomAction.TargetName).CA.dll" />
<CustomAction Id="RegisterServiceNameCustomAction" BinaryKey="RegisterServiceCustomActionBinary" DllEntry="ShowRegisterService" Execute="deferred" Return="check" />
</Fragment>
Here are the different conditions I have tried:
(ServiceType="RegisterNew") AND (NOT Installed)
<![CDATA[(ServiceType="RegisterNew") AND (NOT Installed)]]>
ServiceType="RegisterNew" AND NOT Installed
Here is the code for my custom Dialog where they are selecting making their selection that will change "ServiceType":
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI Id="SelectServiceDlg">
<Property Id="ServiceType" Value="RegisterNew" />
<Dialog Id="SelectServiceDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes">
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="[DialogBitmap]" />
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="40" Transparent="yes" NoPrefix="yes" Text="Determine whether you need to register a new service or link an existing service." />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="Service Type Selection" />
<Control Id="BothScopes" Type="RadioButtonGroup" X="20" Y="55" Width="330" Height="120" Property="ServiceType">
<RadioButtonGroup Property="ServiceType">
<RadioButton Value="RegisterNew" X="0" Y="0" Width="295" Height="16" Text="Register New Service" />
<RadioButton Value="LinkExisting" X="0" Y="60" Width="295" Height="16" Text="Link Existing Service" />
</RadioButtonGroup>
</Control>
<Control Id="RegisterNewServiceDescription" Type="Text" X="33" Y="70" Width="300" Height="36" NoPrefix="yes" Text="Select this option if you are going to register a new service.">
</Control>
<Control Id="LinkExistingDescription" Type="Text" X="33" Y="130" Width="300" Height="36" NoPrefix="yes" Text="Select this option if you are going to link an existing service to this service.">
</Control>
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" />
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
</Dialog>
</UI>
</Fragment>
</Wix>
Here is an image of the UI:
So my question is why is it executing the custom action even though my condition is specifically checking that property?
After some reading of documentation and looking at all of the "properties" of the tag in WIX I decided to try and set a couple of other values and see what happened. I found that when defining the Property if you mark it as secure it then retains its value throughout the entire install process whereas if it is not secure it does not seem to do that. So now my property definition looks like this:
<Property Id="SERVICE_TYPE" Secure="yes" Value="RegisterNew" />
You'll notice that I had to change the name to call caps because when you mark a property as a secure property then you can not have any lowercase letters in the name.
Here is a snippet from the WIX documentation:
Secure -- YesNoType -- Denotes that the property can be passed to the server-side when doing a managed installation with elevated privileges. See the SecureCustomProperties Property for more information.
WIX Documentation For Property Element

Using a condition to make changes to the Windows firewall in WIX

I am trying to make changes to the Windows firewall based on a property that is set in a dialog. I can see in the log that the property is being set correctly but the firewall rules are being created regardless of the value of the property.
My code is...
<Component Id="ChangeFirewall" Guid="*" KeyPath="yes">
<Condition><![CDATA[ChgFirewall = "True"]]></Condition>
<fire:FirewallException Id="FW6501" Name="6501" Port="6501"
Protocol="tcp" Scope="any"/>
<fire:FirewallException Id="FW6502" Name="6502" Port="6502"
Protocol="tcp" Scope="any"/>
<fire:FirewallException Id="FW6505" Name="6505" Port="6505"
Protocol="tcp" Scope="any"/>
</Component>
If ChgFirewall is False why does the firewall get changed?
Update: I have added the code for the dialog that sets the CHGFIREWALL property...
<Dialog Id="FirewallDlg" Width="370" Height="270" Title="[ProductName] Setup" NoMinimize="yes">
<Control Id="Description" Type="Text" X="20" Y="20" Width="280" Height="40" Transparent="yes" NoPrefix="yes">
<Text>This program uses TCP ports 6501, 6501, and 6505 for coordinating information between workstations. These ports must be unblocked for it to work correctly</Text>
</Control>
<Control Id="Instructions" Type="Text" X="20" Y="70" Width="280" Height="30" Transparent="yes" NoPrefix="yes">
<Text>This installer can attempt to automatically modify the Windows Firewall for you, or you may manually modify the firewall settings.</Text>
</Control>
<Control Type="RadioButtonGroup" Property="CHGFIREWALL" Id="CHGFIREWALL" Width="340" Height="44" X="20" Y="120">
<RadioButtonGroup Property="CHGFIREWALL">
<RadioButton Text="Have the installer update the firewwall settings for Guru (Recommended)" Height="13" Value="True" Width="340" X="0" Y="0" />
<RadioButton Text="Manually update the firewall settings" Height="13" Value="False" Width="340" X="0" Y="15" />
</RadioButtonGroup>
</Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next">
<Publish Event="EndDialog" Value="Return"></Publish>
</Control>
<Control Id="CancelButton" Type="PushButton" Text="Cancel" Height="17" Width="56" X="180" Y="243" Cancel="yes">
<Publish Event="EndDialog" Value="Exit" />
</Control>
</Dialog>
Also this is my definition of the property...
<Property Id='CHGFIREWALL' Value='False' Secure='yes'/>
As a first step, UPPERCASE the property and set the attribute 'secure="yes". This ensures that the property is passed properly to the server process as explained in the comments here.
Then the issue is how you set the property? Is is set by a custom action, or do you set it in the Property table or on the command line?

Text template stop working after manual edit

In my installer I want user to connect to database. I support 4 database types in my product.
In the connect to database dialog I created, there is a ComboBox control with all supported database types, Edit control where user suppose to enter the connection string and a PushButton, when pressed it will show connection string text template in Edit control according to selected database type in ComboBox. Now, the problem is:
User clicks Show Template button when MSSQL is selected
User alters manually place holder in text template connection string in Edit
control
User realize that he needs MySQL connection
User change value in ComboBox to MySQL and clicks Show Template button and nothing
happens.
To summarize this, after Edit control were manually altered, the Show Template stops working.
Here is WiX code use:
<Fragment>
<!-- Supported databases templates -->
<Property Id="MSSQLTemplate" Value="Data Source=localhost;Initial Catalog=[database];Integrated Security=yes"/>
<Property Id="MySQLTemplate" Value="Server=localhost;Uid=[username];Pwd=[password];Database=[database];" />
<Property Id="DB2Template" Value="Server=localhost;Uid=[username];Pwd=[password];Database=[database];" />
<Property Id="OracleTemplate" Value="Data Source=[database];User Id=[username];Password=[password];" />
<Property Id="PROP_DATABASE_TYPE">MSSQL</Property>
<Property Id="PROP_CONNECTIONSTRING"></Property>
<Binary Id="CA_DLL" SourceFile="$(var.CustomActions.TargetDir)CustomActions.CA.dll" />
<CustomAction Id="caShowTemplate" BinaryKey="CA_DLL" DllEntry="ShowTemplate" Execute="immediate" />
<UI Id="InstallDlg_UI">
<TextStyle Id="Tahoma_Regular" FaceName="Tahoma" Size="8" />
<Property Id="DefaultUIFont" Value="Tahoma_Regular" />
<Dialog Id="InstallDlg" Width="370" Height="270" Title="Amazing Software" NoMinimize="no">
<!-- Database type -->
<Control Id="lblDatabaseType" Type="Text" X="20" Width="100" Y="60" Height="18" NoPrefix="yes" Text="Database Type" />
<Control Id="cbDatabaseServer" Type="ComboBox" X="120" Width="90" Y="60" Height="18" Property="PROP_DATABASE_TYPE" ComboList="yes" Sorted="yes">
<ComboBox Property="PROP_DATABASE_TYPE">
<ListItem Text="MSSQL" Value="MSSQL" />
<ListItem Text="MySQL" Value="MySQL" />
<ListItem Text="Oracle" Value="Oracle" />
<ListItem Text="DB2" Value="DB2" />
</ComboBox>
</Control>
<Control Id="btnShowTemplate" Type="PushButton" X="215" Y="60" Width="85" Height="17" Text="Show Template">
<Publish Event="DoAction" Value="caShowTemplate" Order="1">1</Publish>
<Publish Property="PROP_CONNECTIONSTRING" Value="[PROP_CONNECTIONSTRING]" Order="2">1</Publish>
</Control>
<!-- Connection string -->
<Control Id="lblConnectionString" Type="Text" X="20" Width="100" Y="85" Height="18" NoPrefix="yes" Text="Connection String" />
<Control Id="tbConnectionString" Type="Edit" X="120" Width="180" Y="85" Height="18" Property="PROP_CONNECTIONSTRING" Text="[PROP_CONNECTIONSTRING]" />
<Control Id="CancelButton" Type="PushButton" Text="Cancel" Height="17" Width="56" X="180" Y="243" Cancel="yes">
<Publish Event="EndDialog" Value="Exit" />
</Control>
</Dialog>
<InstallUISequence>
<Show Dialog="InstallDlg" Before="ExecuteAction" />
</InstallUISequence>
</UI>
</Fragment>
And a custom action written in C#:
[CustomAction]
public static ActionResult ShowTemplate(Session session)
{
string selectedDatabase = string.Format("{0}Template", session["PROP_DATABASE_TYPE"]);
session["PROP_CONNECTIONSTRING"] = session[selectedDatabase];
return ActionResult.Success;
}
What am I doing wrong?
Your code doesn’t have any issue. It is a well-known limitation of WIX UI. Check the below discussions for more details.
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/UI-Edit-Box-not-updating-td5077648.html
Wix Interactions with Conditions, Properties & Custom Actions

WIX UI - Creating a "passwords don't match" label

I need my installer to accept a password, and so I've created a dialog on which users are prompted to enter their passwords twice (to avoid mistakes), however I'm having some trouble getting my "Your passwords don't match" label to appear and disappear at the correct times.
This is what I have so far:
<Control Id="Password" Type="Edit" Property="VDIR_PASSWORD" Password="yes" />
<Control Id="ConfirmPassword" Type="Edit" Property="ConfirmPassword" Password="yes" />
<Control Id="PasswordMismatchLabel" Type="Text" Text="Passwords do not match.">
<Condition Action="hide">VDIR_PASSWORD = ConfirmPassword</Condition>
</Control>
This compiles, however does the label never shows. (if I reverse the condition then the label shows, but doesn't disappear if they don't match).
I can see that the thing I'm missing is subscription to some event that updates the label whenever something happens (e.g. the user presses a key, or focus is lost from either of the controls), however I'm not able to find any documentation or examples of how I might achieve this.
Is it possible to do this?
Here is an example of what Yan is suggesting:
<Control Id="Next" Type="PushButton" X="238" Y="243" Width="56" Height="17" Text="Next">
<Publish Event="NewDialog" Value="VirtualDirectoryDlg">1</Publish>
<Condition Action="disable">
<![CDATA[(ACCOUNT_TYPE = "Service" AND WEB_APP_POOL_SERVICE_NAME = "") OR
(ACCOUNT_TYPE = "User" AND
((WEB_APP_POOL_IDENTITY_DOMAIN = "" OR
WEB_APP_POOL_IDENTITY_NAME = "" OR
WEB_APP_POOL_IDENTITY_PWD = "" OR
WEB_APP_POOL_IDENTITY_PWD_CONFIRM = "") OR (WEB_APP_POOL_IDENTITY_PWD <> WEB_APP_POOL_IDENTITY_PWD_CONFIRM))) ]]>
</Condition>
<Condition Action="enable">
<![CDATA[(ACCOUNT_TYPE = "Service" AND WEB_APP_POOL_SERVICE_NAME <> "") OR
(ACCOUNT_TYPE = "User" AND
((WEB_APP_POOL_IDENTITY_DOMAIN <> "" AND
WEB_APP_POOL_IDENTITY_NAME <> "" AND
WEB_APP_POOL_IDENTITY_PWD <> "" AND
WEB_APP_POOL_IDENTITY_PWD_CONFIRM <> "") AND (WEB_APP_POOL_IDENTITY_PWD = WEB_APP_POOL_IDENTITY_PWD_CONFIRM))) ]]>
</Condition>
</Control>
Here's the approach I took to solve this issue. This solution does not rely on disabling the "Next" button. Instead, it recognizes three states during the password comparison, but doesn't allow a user to proceed unless 1) both the password fields are populated, and 2) both password fields match. This solution also provides text labels to let the user better understand when there are errors states.
Hopefully this solution will help others.
The three states:
Passwords match
Passwords do not match
Passwords match, but are empty strings
Error states:
"Passwords do not match"
"Password fields required"
To get the red, slightly larger than normal text, by adding the following TextStyle element into my primary wxs file (e.g. product.wxs).
<UI>
<TextStyle Id="WixUI_Font_Large_Red" FaceName="Tahoma" Size="9" Red="255" />
</UI>
Here's the
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Property Id="PASSWORD_COMPARE" Value="1" />
<UI>
<Dialog Id="ConfirmPasswordDlg" Width="370" Height="270" Title="Confirm Password Demo">
<Control Id="PasswdLabel" Type="Text" X="25" Y="65" Width="90" Height="15" TabSkip="no" Text="Password:" RightAligned="yes" />
<Control Id="PasswdEdit" Type="Edit" X="117" Y="62" Width="175" Height="16" Property="PASSWD" Text="{80}" Password="yes"></Control>
<Control Id="ConfirmPasswdLabel" Type="Text" X="25" Y="90" Width="90" Height="15" TabSkip="no" Text="Confirm Password:" RightAligned="yes" />
<Control Id="ConfirmPasswdEdit" Type="Edit" X="117" Y="87" Width="175" Height="16" Property="PASSWD_CONFIRM" Text="{80}" Password="yes"></Control>
<Control Id="PasswordsMatchLabel" Type="Text" X="150" Y="110" Width="140" Height="18" Text="{\WixUI_Font_Large_Red}Passwords do not match">
<Condition Action="hide">(PASSWORD_COMPARE = "1")</Condition>
<Condition Action="show">(PASSWORD_COMPARE = "2")</Condition>
<Condition Action="hide">(PASSWORD_COMPARE = "3")</Condition>
</Control>
<Control Id="PasswordsRequiredLabel" Type="Text" X="150" Y="110" Width="140" Height="18" Text="{\WixUI_Font_Large_Red}Password fields required">
<Condition Action="hide">(PASSWORD_COMPARE = "1")</Condition>
<Condition Action="hide">(PASSWORD_COMPARE = "2")</Condition>
<Condition Action="show">(PASSWORD_COMPARE = "3")</Condition>
</Control>
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="Back"></Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next">
<Publish Property="PASSWORD_COMPARE" Value="1" Order="1">
<![CDATA[ (PASSWD = PASSWD_CONFIRM) ]]>
</Publish>
<Publish Property="PASSWORD_COMPARE" Value="2" Order="2">
<![CDATA[ (PASSWD <> PASSWD_CONFIRM) ]]>
</Publish>
<Publish Property="PASSWORD_COMPARE" Value="3" Order="3">
<![CDATA[ (PASSWD = "" AND PASSWD_CONFIRM = "") ]]>
</Publish>
<Publish Event="NewDialog" Value="VerifyReadyDlg" Order="4">PASSWORD_COMPARE = "1"</Publish>
</Control>
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
</Dialog>
</UI>
</Fragment>
</Wix>
WiX can only do what underlying technology (Windows Installer) can. Windows Installer has poor UI comparing to usual desktop applications we all used to. So, answering your question: no, you can't show/hide the label based on the value you've typed into the password field. At least, I'm not aware about a supported way.
However, you can do the following. Drop that label, and instead add a condition to the Next button of this dialog. If passwords match, move to the next dialog in the chain. Otherwise, show a message box saying "password don't match" and stay on the current dialog until the user fills it in correctly.
Hope this helps.
As far as I'm aware, there is no event subscription model in Wix. What you'll likely have to do is create a custom action to verify that the passwords match and have that control the label. This may help also.

WiX: property value lost between InstallUISequence and InstallExecuteSequence

I'm facing an issue with my WiX installer.
I have a custom dialog that contains an edit control linked to a property. At runtime, if I change the value in the edit control, I see from the log that the property is properly updated with that new value. But it seems that, when the InstallUISequence ends, the property is reset to its default value, which is annoying, because I cannot use the user sumitted value in a custom action part of the InstallExecuteSequence.
Here is an extract of the WXS script I use:
<UI>
<Dialog Id="select_list" Width="370" Height="270" Title="Select license and list files">
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="UIBannerBmp" />
<Control Id="BannerLine" Type="Line" X="0" Y="45" Width="370" Height="0" />
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Type="Edit" Id="list" Width="211" Height="15" X="128" Y="128" Property="pListFile" />
<Control Type="Text" Id="static_list" Width="78" Height="17" X="41" Y="154" Text="list file" />
<Control Type="PushButton" Id="next" Width="50" Height="17" X="232" Y="244" Text="Next >">
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>
<Control Type="PushButton" Id="cancel" Width="50" Height="17" X="296" Y="244" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Type="Text" Id="desc" Width="348" Height="16" X="8" Y="90"
Text="Please set the path of the the list file" />
</Dialog>
<InstallUISequence>
<Show Dialog="select_list" After="WelcomeEulaDlg">NOT installed</Show>
</InstallUISequence>
</UI>
<CustomAction Id="InstallService"
ExeCommand="[bin]prog.exe -f install.cl '[pListFile]'"
Execute="immediate"
Return="check"
Directory="bin" />
<InstallExecuteSequence>
<Custom Action="InstallService" After="InstallFinalize">REMOVE=""</Custom>
</InstallExecuteSequence>
<CustomActionRef Id="InstallService" />
<Property Id="pListFile" Value="c:\" />
I must not be on the right track to exchange information between the two sequences.
Is there a way to do that?
You need to mark the Property "Secure" for it to pass from the client-side (InstallUISequence) to server-side (InstallExecuteSequence). To do that you need to make the Property "public" (ALL CAPS) and secure. Something like so:
<Property Id="PLISTFILE" Secure="yes"/>
You don't need to give it a value unless you want something to show up by in your UI by default.