Combining features conditions in a new property - wix

I have a Wix setupKit I have a few features that based on them some custom dialogs will be displayed. There are some conditions that I want to combine them in a new property. For example:
<Property Id="SERVERSETTINGSISNEEDED">
<![CDATA[(&Client = 3) OR (!Client = 3) OR (&CoreService = 3) OR (!CoreService = 3) OR (&ResourceService = 3) OR (!ResourceService = 3)]]>
</Property>
and then:
<Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="ServersSettingsDlg" Order="1">SERVERSETTINGSISNEEDED</Publish>
But it does not work and always show that dialog.
Any help is appreciated.

When you define an MSI property with the <Property> element in WiX, it is constructed at build time and you end up having a record in the Property table by the time MSI package is built. On the other hand, the feature states are resolved at run time, that is, when your package is being installed.
Hence, you try to reference runtime values during build time, which is not correct. I'm sure it can be explained why the resulting property evaluates to true, but that's not the question.
As far as I understand your question, you'd like to shorten the condition part of the element in order not to copy/paste the long string a number of times. If that's the case, you don't have to involve the MSI properties here - you can achieve this with WiX preprocessor feature.
So, do the following:
define the condition as a preprocessor variable:
<?define ServerSetingIsNeeded = "(&Client = 3) OR (!Client = 3) OR (&CoreService = 3) OR (!CoreService = 3) OR (&ResourceService = 3) OR (!ResourceService = 3)>"?>
use the variable instead of condition:
<Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="ServersSettingsDlg" Order="1">$(var.ServerSetingIsNeeded)</Publish>

Related

In a WiX installer how do you determine which features have been selected for installation?

I am using WiX Toolset v3.11 and would like to find out the state of the features after the user has made selections by using a Selection Tree in the Custom dialog.
For example, I have this feature:
<Feature Id="Miscellaneous" Title="Miscellaneous" Description="Stuff." Level="4" ConfigurableDirectory="INSTALLFOLDER">
<MergeRef Id="miscMM"/>
</Feature>
How can I test if this features has been selected to be installed?
I am trying to set a property that will be used in the final dialog that will summarize the features that will be installed.
For the Next button that opens the Summary Dialog I have tried this:
<Publish Property="INST_MISC" Value="Yes"><![CDATA[Miscellaneous <> "4"]]></Publish>
but it always evaluates to true regardless of the Selection Tree setting.
Thanks.
This seems to do what I want:
<Publish Property="INST_MISC" Value="Yes"><![CDATA[(&Miscellaneous AND &Miscellaneous=3)]]></Publish>
<Publish Property="INST_MISC" Value="No"><![CDATA[NOT &Miscellaneous OR (&Miscellaneous AND &Miscellaneous<>3)]]></Publish>
<Publish Property="INST_MISC" Value="When required"><![CDATA[(&Miscellaneous AND &Miscellaneous=1)]]></Publish>

Checking port value using CDATA in WiX

I want to have a port number validation in my WiX installer. Using one of codes below, I try to check if a database port has a value between 1024 and 65535:
1. <Publish Event="SpawnDialog" Value="InvalidPortNumber"><![CDATA[(DATABASE_PORT < 1024 OR DATABASE_PORT > 65535)]]></Publish>
2. <Publish Event="SpawnDialog" Value="InvalidPortNumber"><![CDATA[(DATABASE_PORT < "1024" OR DATABASE_PORT > "65535")]]></Publish>
But none of them do not publish a spawn dialog if the user writes a port number less than 1024. For value greater than 65535 everything works good.
The port number is set in:
<Control Id="DatabasePortText" Type="MaskedEdit" X="20" Y="120" Width="50" Height="15" Property="DATABASE_PORT" Text="######"/>
How can I fix this problem?
The problem is that your property is treated as string, thus < and > don't really make sense in the way that it should.
You have two choices:
Use Edit control and set Integer attribute as yes: <Control Type="Edit" Integer="yes" .../>. This will make sure that property is treated as integer.
Use MaskedEdit, and when you press Next button, a custom action will be executed which can convert string property into integer property.

Wix Installer - ICE03: Not a valid foreign key

I'm really struggling trying to figure these error out. I'm trying to build a setup using the following sequence:
Welcome Screen
License Screen
Scope Screen
Browse Screen
Features Screen
Custom Screen
Shortcut Screen
Install Overview Screen
Install/Progress Screen
Finish Screen
Rather that jumping into the lot in one go, I thought I'd do them one by one and I got as far as building the Welcome, License, Scope screen.
I then tried to include the Features Screen but I had the error I'll explain below. Strangely enough when I change the FeatureDlg to CustomizeDlg it works.
I then try to introduce the BrowseDlg before the CustomizeDlg but now I keep getting similar errors when I tried to use the FeaturesDlg.
I'm new to Wix so apologies if I've left something obvious out. I'm using VS2013 to build this.
My UI.Wxs has the following code within its UI tags
<DialogRef Id="BrowseDlg" />
<DialogRef Id="DiskCostDlg" />
<DialogRef Id="ErrorDlg" />
<DialogRef Id="FatalError" />
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<DialogRef Id="PrepareDlg" />
<DialogRef Id="ProgressDlg" />
<DialogRef Id="ResumeDlg" />
<DialogRef Id="UserExit" />
<!--<DialogRef Id="FeaturesDlg" />-->
<DialogRef Id="CustomizeDlg" />
<!-- Welcome -->
<Publish Dialog="WelcomeDlg"
Control="Next"
Event="NewDialog"
Value="LicenseAgreementDlg">NOT Installed</Publish>
<!-- License -->
<Publish Dialog="LicenseAgreementDlg"
Control="Back"
Event="NewDialog"
Value="WelcomeDlg">1</Publish>
<Publish Dialog="LicenseAgreementDlg"
Control="Next"
Event="NewDialog"
Value="InstallScopeDlg">LicenseAccepted = "1"</Publish>
<!-- Scope -->
<Publish Dialog="InstallScopeDlg"
Control="Back"
Event="NewDialog"
Value="LicenseAgreementDlg">1</Publish>
<Publish Dialog="InstallScopeDlg"
Control="Next"
Event="NewDialog"
Value="BrowseDlg">1</Publish>
<!-- BrowseDlg -->
<Publish Dialog="BrowseDlg"
Control="Back"
Event="NewDialog"
Value="InstallScopeDlg">1</Publish>
<Publish Dialog="BrowseDlg"
Control="Next"
Event="NewDialog"
Value="CustomizeDlg">1</Publish>
<!-- Features -->
<Publish Dialog="CustomizeDlg"
Control="Back"
Event="NewDialog"
Value="BrowseDlg">1</Publish>
<Publish Dialog="CustomizeDlg"
Control="Next"
Event="NewDialog"
Value="CustomFeaturesDlg">1</Publish>
<!--Custom Features--><!--
<Publish Dialog="CustomFeaturesDlg"
Control="Back"
Event="NewDialog"
Value="FeaturesDlg">1</Publish>
<Publish Dialog="CustomFeaturesDlg"
Control="Finish"
Event="EndDialog"
Value="Return">1</Publish>-->
<!-- Finished -->
<Publish Dialog="ExitDialog"
Control="Finish"
Event="EndDialog"
Value="Return"
Order="999">1</Publish>
<UIRef Id="WixUI_Common" />
Now the error's I'm getting are:
Error 1 ICE03: Not a valid foreign key; Table: ControlEvent, Column: Control_, Key(s): BrowseDlg.Back.NewDialog.InstallScopeDlg.1
Error 2 ICE03: Not a valid foreign key; Table: ControlEvent, Column: Control_, Key(s): BrowseDlg.Next.NewDialog.CustomizeDlg.1
Error 3 ICE03: Not a valid foreign key; Table: ControlEvent, Column: Control_, Key(s): CustomFeaturesDlg.Finish.EndDialog.Return.1
Error 4 ICE03: Not a valid foreign key; Table: ControlEvent, Column: Control_, Key(s): CustomFeaturesDlg.Back.NewDialog.FeaturesDlg.1
Error 5 ICE17: PushButton: 'Back' of Dialog: 'FeaturesDlg' does not have an event defined in the ControlEvent table. It is a 'Do Nothing' button.
I'm not too worried about the last one... But the 'Foreign' key error is driving me mad.
Can anyone point me in the right direction?
Thanks.
I guess you wanted to use InstallDirDlg instead of BrowseDlg. BrowseDlg is just the folder-selection dialog which is opened from InstallDirDlg when you want to change default installation location. It contains buttons OK and Cancel (there is no Back and Next).
Look here for an example: WiX installer fails with error code 2819 (and don't forget to add WIXUI_INSTALLDIR property - see the comments below).
For the CustomFeaturesDlg it's most likely the same story.
You can check this answer for some overall ICE info (recommended read if you are unsure what ICE checks do). Here is the ICE03 MSDN page - as you see there are many different errors possible in this particular ICE since it is concerned with overall database referential integrity (that the foreign keys match in linked tables so that they can be joined).
I have never dealt with dialogs in Wix this way, I always just use the default dialog set as explained here - it is nice and simple and does the job auto-magically. However, I have dealt with Installshield dialogs in sequence, and it is always a matter of syncing up the next and previous button events on each dialog to allow the proper dialog sequence to unfold as the buttons are pressed. It works like a doubly linked list of sorts with proper pointers to what the next dialog should be. If messed up the dialogs show up haphazardly - which can turn into very strange behavior. For example a button might not work at all, it might take you to the wrong dialog or it could even start the whole install prematurely.
In conclusion: you need to go over the compiled MSI to verify that the dialog sequence is working, both interactively whilst running the setup, and by inspecting the compiled MSI using Orca or a similar tool. Perhaps this description of Orca is helpful too? I have seen foreign key problems like this relate to capitalization or even whitespace, or a genuine mismatch.

WIX WixUI_InstallMode property and quotes weird behavior

I faced very strange behavior of WIX installer conditions, using WixUI_InstallMode property.
It behaves completely different in conditions of element and in conditions of elements. For example, this condition correctly leads to MaintenanceTypeDlg only when remove or repair option was used:
<UI>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="6"><![CDATA[WixUI_InstallMode = "Repair" OR WixUI_InstallMode = "Remove"]]></Publish>
</UI>
while this one never shows the previous dialog:
<UI>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="6"><![CDATA[WixUI_InstallMode = Repair OR WixUI_InstallMode = Remove]]></Publish>
</UI>
The only difference is that "Repair" and "Remove" values are without quotes in the second example. So it looks like normal and we should put values in quotes, like it is in WIX sources.
But let's consider two more examples:
<InstallExecuteSequence>
<Custom Action="AssertUserCredentials" After="InstallValidate"><![CDATA[WixUI_InstallMode<>"Remove"]]></Custom>
</InstallExecuteSequence>
This condition is always true. So in remove mode the custom action is fired which is completely unexpected. Why is it fired?
And again example withot quotes:
<InstallExecuteSequence>
<Custom Action="AssertUserCredentials" After="InstallValidate"><![CDATA[WixUI_InstallMode<>Remove]]></Custom>
</InstallExecuteSequence>
This now works fine without quotes and don't execute custom action in uninstall mode.
As for me, these two usages of conditions are completely the same logic, but the behavior is completely opposite. Can anybody explain what happens?

How to display a non-blocking warning for the operating system in Wix?

I already block installation of our software on operating systems where it is known not to work like this:
<Condition Message="This software needs Windows XP or newer.">
<![CDATA[VersionNT >= 501]]>
</Condition>
Now I would also like to display a non-blocking warning if the user tries to install the software on an operating system (VersionNT + Service Pack) that is not explicitly supported, even though it might work.
For example, we only explicitly support the latest service pack of each operating system.
How can I display such a warning?
I tackled this problem in 3 parts:
defining an OSWarningText property
which is only set when a warning
needs to be given
authoring a custom warning screen
Inserting the custom warning screen in the UI sequence if necessary
1. Defining an OSWarningText property
First, declare the property and give it the "unset" value by default:
<Property Id="OSWarningText" Value="{}"/>
To construct the actual value of the property, set an intermediary property for each possible warning. Make sure the conditions for each warning do not overlap:
<SetProperty Id="OSWarningText1" After="AppSearch"
Value="Detected XP SP [ServicePackLevel]. SP3 or higher is recommended.">
<![CDATA[(VersionNT = 501) AND NOT (ServicePackLevel >= 3)]]>
</SetProperty>
<SetProperty Id="OSWarningText2" After="SetOSWarningText1"
Value="Detected Vista SP [ServicePackLevel]. SP2 or higher is recommended.">
<![CDATA[(VersionNT = 600) AND NOT (ServicePackLevel >= 2)]]>
</SetProperty>
Assuming the conditions don't overlap, we can safely condense the warnings in a single property like this:
<SetProperty Id="OSWarningText" After="SetOSWarningText2"
Value="[OSWarningText1][OSWarningText2]" />
2. Authoring a custom warning screen.
This is similar to the example for adding a checkbox for the desktop shortcut. Copy one of the existing dialog definitions from the wix sources, e.g. InstallDirDlg.wxs and rename it to WarningDlg.wxs.
Set the dialog ID to Id="WarningDlg. Strip out the unnecessary controls and replace them by a warning image and our previously defined OSWarningText:
<Control Id="OSWarning" Type="Text" X="100" Y="80" Width="250" Height="60"
NoPrefix="yes" Text="[OSWarningText]" />
<Control Id="WarningIcon" Type="Icon" X="20" Y="60" Width="64" Height="64"
Text="Warning.ico" >
<Binary Id="Warning.ico" SourceFile="..\icons\warning.ico"/>
</Control>
The idea is to create something like this:
3. Inserting the custom warning screen in the UI sequence
Now we need to make sure that the warning screen is displayed between the welcome dialog and the license agreement dialog, but only if there actually is a warning to show. This is a special case of the more general branching wizard sequences problem.
Again, copy a predefined UI sequence from the wix sources, e.g. WixUI_InstallDir.wxs and rename the UI ID to Id="MyWixUI". Reference this in your main wxs file as <UIRef Id="MyWixUI" />. Now find and edit the event handlers for the WelcomeDlg next button.
You can set properties in response to a button press and an extra condition, and you can show the next dialog based on a property. We'll make use of that to handle the WelcomeDlg next button like this:
reset the WelcomeDlg_Next property
to "unset"
set the WelcomeDlg_Next property to
"WarningDlg" but only if
OSWarningText is set
set the WelcomeDlg_Next property to
"LicenseAgreementDlg" but only if
OSWarningText is NOT set.
Show the dialog given by
WelcomeDlg_Next, if the property was
correctly set.
The Wix code to do that looks like this:
<Publish Dialog="WelcomeDlg" Control="Next"
Property="WelcomeDlg_Next" Value="{}"
Order="1">1</Publish>
<Publish Dialog="WelcomeDlg" Control="Next"
Property="WelcomeDlg_Next" Value="WarningDlg"
Order="2">OSWarningText</Publish>
<Publish Dialog="WelcomeDlg" Control="Next"
Property="WelcomeDlg_Next" Value="LicenseAgreementDlg"
Order="3">NOT OSWarningText</Publish>
<Publish Dialog="WelcomeDlg" Control="Next"
Event="NewDialog" Value="[WelcomeDlg_Next]"
Order="4">WelcomeDlg_Next</Publish>
Then do the equivalent for the License Agreement "back" button: it should go back to the welcome screen if there is no warning, or else to the warning screen.