Checking port value using CDATA in WiX - 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.

Related

WiX: how to expand the variable which is used in the localized string?

WiX.
This is my localized String:
<String Id="SelectInstallDir_WARNING_Text">Don't select the "$(env.ProgramData)\Autodesk\ApplicationPlugins\ProxyTools.bundle\" variant if you will use AutoCAD 2012, because its bundle-autoloader don't monitor of that directory.</String>
I use that string here:
<Control Id="warning_acad2012_text" Type="Text" X="10" Y="170" Width="350" Height="60"
Transparent="yes" NoPrefix="yes">
<Text>{\DlgFont10_important}!(loc.SelectInstallDir_WARNING_Text)</Text>
</Control>
But I see that $(env.ProgramData) variable wasn't expanded.
How can I fix it?
Assuming you want the current value at install time, instead of the value from the build machine, you should Windows Installer's formatting. Specifically you should reference a directory property such as "... [CommonAppDataFolder] ..." or an environment variable such as "... [%ProgramData] ...".

WIX Property as Integer

I am trying to set a a property to configure the IIS:Website ConnectionTimeout value on a new website that gets created during setup.
However I am unable to, as the value for ConnectionTimeout must be an integer, not string.
In my product.wxs I have the following:
<Control Id="IisConnectionTimeoutLabel" Type="Text" X="45" Y="164" Width="100" Height="15" TabSkip="no" Text="Connection Timeout (sec):" />
<Control Id="IisConnectionTimeoutEdit" Type="Edit" X="45" Y="176" Width="220" Height="18" Property="IIS_CONNECTIONTIMEOUT" Text="{80}" Integer="yes" />
And in my IisConfiguration.wxs I have the following:
<Property Id="IIS_CONNECTIONTIMEOUT" Value="300" />
<iis:WebSite Id="EersWebsite" Description="[IIS_WEBSITENAME]" ConfigureIfExists="yes" Directory="WEBINSTALLDIR" DirProperties="EersWebsiteDirProperties" ConnectionTimeout="[IIS_CONNECTIONTIMEOUT]">
When I build the project I get the following:
The 'ConnectionTimeout' attribute is invalid - The value
'[IIS_CONNECTIONTIMEOUT]' is invalid according to its datatype
'http://www.w3.org/2001/XMLSchema:nonNegativeInteger' - The string
'[IIS_CONNECTIONTIMEOUT]' is not a valid Integer value.
The iis:WebSite/#ConnectionTimeout attribute's value,
'[IIS_CONNECTIONTIMEOUT]', is not a legal integer value. Legal
integer values are from -2,147,483,648 to 2,147,483,647.
Thanks in advance
As the error message states, the value of the <iis:WebSite>'s ConnectionTimeout attribute expects the integer value. The nonNegativeInteger is not a Formatted type, which knows how to extract values out of properties provided in square brackets.
Hence, I don't think you have a way here apart from providing the hard-coded value...
Alternatively, you can create a custom action, which calls for appcmd.exe, and provide the required timeout value in the command-line, and schedule this action deferred after ConfitureIIs... But the efforts seem much bigger than the benefit...

checking the registration number entered by user

I was trying to use a custom dll for checking the registration number entered by user, but I run every time into “magic” behavior. In the tutorial examples http://wix.tramontana.co.hu/tutorial/events-and-actions/whats-not-in-the-book the custom action is running after ‘CostFinalize’, which normally should be before file copying procedure, but it turns out that the action runs before the very first dialog box with License Agreement appears. I have tried to solve the problem by assigning an action on the event of clicking the “next” button in registration Dialog
<Publish Dialog="MySerialCheckDlg" Control="Next" Event="DoAction" Value="CheckingPID">1</Publish>
<Publish Dialog="MySerialCheckDlg" Control="Next" Event="SpawnDialog" Value="InvalidPidDlg">PIDACCEPTED = "0"</Publish>
...
<CustomAction Id="CheckingPID" BinaryKey="CheckPID" DllEntry="CheckPID" />
<Binary Id="CheckPID" SourceFile="serialcheck.dll" />
In dll, using MsiGetProperty (hInstall, "PIDKEY", Pid, &PidLen); does not get the PIDKEY value from msi specified in MySerialCheckDlg UI
<Control Id="CDKeyEdit" Type="Edit" X="45" Y="159" Width="220" Height="16" Property="PIDKEY" Text="[PIDTemplate]" />
And in the msi the PIDACCEPTED property is not been checked in the line
<Publish Dialog="MySerialCheckDlg" Control="Next" Event="SpawnDialog" Value="InvalidPidDlg">PIDACCEPTED = "0"</Publish>
Thus, the InvalidPidDlg does not appear, and the installation process continues further.
Can you please specify the order of WiX Action Sequence, or maybe specify any other approach which can be used in this situation.
There are two sequences: InstallExecuteSequence and InstallUISequence. If MSI runs with full UI, it executes actions from InstallUISequence; in case where no UI is shown, these actions are skipped. Actions from InstallExecuteSequence are executed during the installation process, with or without UI.
First of all, is your PIDKEY property tied to an edit control? You should something similar in the dialog where you ask users to type in PIDKEY:
<Control Id="PidKeyEdit" Type="Edit" X="45" Y="105" Width="220" Height="18" Property="PIDKEY" Text="{80}" />
Type could be either Edit or MaskedEdit. Publish elements should be associated with Next button control on the dialog:
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17"
Default="yes" Text="Next">
<Publish Event="DoAction" Value="CheckingPID">1</Publish>
<Publish Event="SpawnDialog" Value="InvalidPidDlg">PIDACCEPTED = "0"</Publish>
</Control>
Run your installation with verbose logging to see how actions are executed, and how property values change:
msiexec /i your-product.msi /lv* your-product.log

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.

How to inspect a CustomAction's property (Wix)?

I am trying to put together a small 'prerequisites' dialog in Wix to give confidence to the users that they have all of the required things needed to run my software:
For example, I have a need for Managed DirectX, so I look for some DLLs:
<Property Id="MANAGED_DIRECTX">
<DirectorySearch Path="$(env.SystemRoot)\Microsoft.NET\DirectX for Managed Code\1.0.2902.0" Depth="0" Id="MDXDir">
<FileSearch Name="Microsoft.DirectX.dll"/>
</DirectorySearch>
</Property>
<Property Id="MANAGED_DIRECTX_DIRECTINPUT">
<DirectorySearch Path="$(env.SystemRoot)\Microsoft.NET\DirectX for Managed Code\1.0.2902.0" Depth="0" Id="MDXInputDir">
<FileSearch Name="Microsoft.DirectX.DirectInput.dll"/>
</DirectorySearch>
</Property>
I also have a CustomAction to combine my condition logic:
<CustomAction Id="SetManagedDirectXInstalled"
Property="MANAGED_DIRECTX_INSTALLED"
Value="NOT([MANAGED_DIRECTX] = '') AND NOT ([MANAGED_DIRECTX_DIRECTINPUT] = ''")/>
This CustomAction is sequenced:
<InstallExecuteSequence>
<Custom Action="SetManagedDirectXInstalled" After="AppSearch" />
<RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>
What I should now be able to do is use "MANAGED DIRECTX INSTALLED" to do something, e.g.
<Control Id="NoManagedDirectX" Type="Text" X="20" Y="50" Width="300" Height="60" Transparent="yes" NoPrefix="yes" Hidden="yes">
<Text>Microsoft Managed DirectX (MDX) for DirectX 9.0 is NOT installed</Text>
<Condition Action="show">NOT MANAGED_DIRECTX_INSTALLED</Condition>
</Control>
<Control Id="ManagedDirectX" Type="Text" X="20" Y="50" Width="300" Height="60" Transparent="yes" NoPrefix="yes" Hidden="yes">
<Text>Microsoft Managed DirectX (MDX) for DirectX 9.0 is correctly installed</Text>
<Condition Action="show">MANAGED_DIRECTX_INSTALLED</Condition>
</Control>
It doesn't matter what I do, the condition is always false (e.g. not installed) even when I know the files are there. Using the msiexec command with /l*vx does not show the MANAGED DIRECTX INSTALLED property anywhere.
When a <Condition> is used with the following, it successfully prevents installation (although I no longer want to block installs in this case, just advise).
<Condition Message="You must have Microsoft Managed DirectX (MDX) for DirectX 9.0 installed">
MANAGED_DIRECTX AND MANAGED_DIRECTX_DIRECTINPUT
</Condition>
How can I trace/debug this (or what have I done wrong?)
EDIT - I'm now certain that my CustomAction is not even being called, setting it to the following is not showing expected results either!
<CustomAction Id='SetManagedDirectXInstalled'
Property='MANAGED_DIRECTX_INSTALLED'
Value='Something hard-coded'/>
or
<CustomAction Id='SetManagedDirectXInstalled'
Error='Some error should show!'/>
I think I may have found the answer, but I can't try it until I'm next at my development PC.
It appears I have to compare the values to TRUE/FALSE (or empty string) not just expecting it to work as boolean (Source)
In these expressions, you can use
property names (remember that they are
case sensitive). Non-existent property
names will be treated as empty
strings. The logical value of a
property reflects whether it has been
set—meaning that you cannot check for
a logical value by simply using the
property:
PROPERTY
This will evaluate to true if the property has been set and has any
value, even if this value is false.
NOT PROPERTY
This will evaluate to true if the property has not been set at all.
PROPERTY = TRUE
PROPERTY = FALSE
This is the proper way to check the value of a logical property.
To debug, use a verbose log file. It will show you the states of your Properties as they change. You should then be able to evaluate the Condition with that knowledge
I answered this same question not too long ago here. A Condition that uses the Property name is a test for existence. An existence test for a Property evaluates to true if the Property has any value at all. If you want to check the value of a Property you need to do so explicitly.