I have created a WiX installer and would like to hide or show a control in last screen when user finish uninstall or install process.
<Control Id="cbxOpenURL" Type="CheckBox" X="135" Y="160" Width="10" Height="10" Property="OPENURLONEXIT" CheckBoxValue="1">
<Condition Action="hide">REMOVE</Condition>
<Condition Action="show">NOT REMOVE</Condition>
</Control>
<Control Id="txtOpenURL" Type="Text" X="150" Y="160" Width="160" Height="20" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDlgOpenurlCheck)" >
<Condition Action="hide">REMOVE</Condition>
<Condition Action="show">NOT REMOVE</Condition>
</Control>
It does not work. What I am doing wrong??
The REMOVE property isn't set until after the InstallValidate action, and that is after the UI dialogs.
The install and uninstall dialog sequences are usually separate (based on each Next value from the starting dialog) so this type of issue doesn't arise when the dialog flows are unique. The sequences typically start based on the Installed property, starting with a Maintenance type of dialog when Installed is set, and with a Welcome type of dialog when Installed is not set, each having their own dialog sequence.
Related
How do I know if I'm upgrading in Wix (v. 3.0.0.0)? I'm trying to bypass some of the data collection screens on an upgrade, and I'm able to create the new path for screens, but I can't figure out what condition to use. One question on the web says PREVFOUND. At this point, I'm not trying to do anything fancy - just show the value on a new screen of mine. My code shows Installed to be true only when the same installer is re-run, so I know I've got the right idea. However, nothing I can figure out shows PREVFOUND as true, and I also can't find anything else that indicates what variable DOES mean "there's a version 1.0 and you're trying to install 1.1". I do have major upgrade set, and it even works, but I want more customization.
<Control Id="PreviousFound" Type="Text" X="1" Y="15" Width="100" Height="15" Text="IsPrevFound:" />
<Control Id="fes" Type="Text" X="80" Y="15" Width="100" Height="15" Text="False" >
<Condition Action="show">NOT PREVFOUND</Condition>
<Condition Action="hide">PREVFOUND</Condition>
</Control>
<Control Id="sfe" Type="Text" X="130" Y="15" Width="100" Height="15" Text="True" >
<Condition Action="show">PREVFOUND</Condition>
<Condition Action="hide">NOT PREVFOUND</Condition>
</Control>
<MajorUpgrade AllowSameVersionUpgrades="yes"
DowngradeErrorMessage="Don't do that!" />
<Product Id="*" Name="$(var.SetupName)" Language="1033" Version="3.4.0.5" Manufacturer="$(var.CompanyLongName)" UpgradeCode="{MY__GUID-EBDE-4221-B203-941E8515A96A}">
That's covered in the MajorUpgrade documentation:
When the FindRelatedProducts action detects a related product installed on the system, it appends the product code to the property named WIX_UPGRADE_DETECTED. After the FindRelatedProducts action is run, the value of the WIX_UPGRADE_DETECTED property is a list of product codes, separated by semicolons (;), detected on the system.
I have a MSI installer and I specify per-machine installation in the installer UI. Previous version was also installed per-machine.
However, FindRelatedProducts reports that current install is per-user.
MSI (c) (A4:F0) [13:33:20:490]: FindRelatedProducts: **current install is per-user**. Related install for product '<<my guid>>' is per-machine. Skipping...
From the log I can see that ALLUSERS property is created only after FindRelatedProducts ran (note timestamp):
MSI (c) (A4:A8) [13:33:25:032]: PROPERTY CHANGE: Adding ALLUSERS property. Its value is '2'.
The property ALLUSERS is Published from the UI based on what the user selected:
<Publish Property="ALLUSERS" Value="2"><![CDATA[FolderForm_AllUsers="ALL" AND VersionNT>=400 AND Privileged=1 AND FolderForm_AllUsersVisible=1]]></Publish>
<Publish Property="ALLUSERS" Value="{}"><![CDATA[FolderForm_AllUsers="ME" AND VersionNT>=400 AND Privileged=1 AND FolderForm_AllUsersVisible=1]]></Publish>
<Control Id="AllUsersRadioGroup" Type="RadioButtonGroup" X="20" Y="175" Width="342" Height="42" Property="FolderForm_AllUsers" Text ="empty">
<RadioButtonGroup Property="FolderForm_AllUsers">
<RadioButton Value="ALL" X="0" Y="0" Width="342" Height="17" Text="$(loc.InstallForAll)" />
<RadioButton Value="ME" X="0" Y="18" Width="342" Height="17" Text="$(loc.InstallForMe)" />
</RadioButtonGroup>
<Condition Action="show"><![CDATA[VersionNT>=400 AND Privileged=1 AND FolderForm_AllUsersVisible=1]]></Condition>
<Condition Action="hide"><![CDATA[NOT (VersionNT>=400 AND Privileged=1 AND FolderForm_AllUsersVisible=1)]]></Condition>
</Control>
As a result, the new version is installed alongside the existing (two entries exist in Add/Remove programs).
<InstallUISequence>
<Custom Action="VSDCA_FolderForm_AllUsers" After="IsolateComponents"><![CDATA[Installed="" AND NOT RESUME AND ALLUSERS=1]]></Custom>
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
</InstallUISequence>
<InstallExecuteSequence>
<!-- Only schedule this custom action for the 32-bit MSI. -->
<?if $(var.DependenciesPlatform)=x86 ?>
<Custom Action="CA_Err32BitMsiOn64BitOS" After="LaunchConditions">
<![CDATA[MsiAMD64 OR Intel64]]>
</Custom>
<?endif ?>
<!-- Prevent downgrading -->
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
<RemoveExistingProducts Before="InstallInitialize" />
<Custom Action="LaunchApp" After="InstallFinalize" />
<InstallInitialize></InstallInitialize>
<RemoveShortcuts></RemoveShortcuts>
<InstallFiles></InstallFiles>
<CreateShortcuts></CreateShortcuts>
<InstallFinalize></InstallFinalize>
<ScheduleReboot After="InstallFinalize"/>
</InstallExecuteSequence>
This occurs only in case both versions of the app are installed per-machine, since FindRelatedProducts apparently assumes per-user installation (because it runs before the user was able to pick one of the radio buttons and therefore there is no ALLUSERS propety set at the time it runs).
How do I ensure that FindRelatedProducts is executed only after ALLUSERS was Published from the UI as specified by the user?
I found I need to add the following to ensure FindRelatedProducts runs within the UI after the user made his choice:
<Publish Event="DoAction" Value="FindRelatedProducts">1</Publish>
From https://www.mail-archive.com/wix-users#lists.sourceforge.net/msg22960.html
I found it is not strictly needed to use the suppress attribute - it seems to work also without explicitly suppressing the action in the InstallUISequence.
I developed an installer using Wix 3.6 that installs successfully all elements of an application.
Now, each time I give an msi with a higher version, I want the installer to prompt the user to uninstall it. Since now I've tried this:
<Product
Id="*"
Name="!(loc.ProductName)"
Language="3082"
Codepage="1252"
Version="1.0.1"
Manufacturer="$(var.ProductManufacturer)"
UpgradeCode="$(var.UpgradeCode)">
<Property Id="PREVIOUSVERSIONINSTALLED" Secure="yes" />
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="1.0.0.0" Maximum="99.9.9.9" IncludeMiminum="yes" IncludeMaximum="no" Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
<InstallExecuteSequence>
<RemoveExistingProducts Before="InstallInitialize" />
</InstallExecuteSequence>
This code successfully uninstalls any previous installed version on my computer. But it doesn't ask the user if he's sure to do so.
What I need is Wix installer to prompt the user saying a message like:
A previous version of your [ProductName] is installed. Do you want to uninstall it? [ Yes | No ] option.
Is there any way to prompt user and check if he really wants to uninstall any previous version?
The Windows Installer Upgrade table has an attribute bit called msidbUpgradeAttributesOnlyDetect that is represented by WiX's UpgradeVersion#OnlyDetect attribute.
When properly authored this causes FindRelatedProducts to set an action property of your choosing with the ProductCode GUID(s) of detected products. It does not pass this off to RemoveExistingProducts for automatic removal though.
While not the typical behavior, there is nothing stopping you from writing some UI that gets triggered when this property has a value. You could ask the user if they want to remove the old version and if yes, set another action property to tell RemoveExistingProducts. (Hint: Author a Upgrade that would never find a product on it's own and hijack it's property to inject the removal. )
If the user says no, you have the choice of aborting the install or continuing the install side by side to a different directory structure. ( Office, Visual Studio et al ).
I found this post useful when solving the same problem. You can use the PREVIOUSVERSIONINSTALLED property you set in the upgrade-tag to open a custom dialog. Do this inside some UI-tags by adding the following code (when using the standard welcome dialog):
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="OldVersionDlg">PREVIOUSVERSIONSINSTALLED</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="SetupTypeDlg">NOT Installed AND NOT PREVIOUSVERSIONSINSTALLED</Publish>
I based my own custom dialog on this Wix tutorial, and ended up with the following code:
<Dialog Id="OldVersionDlg" Width="260" Height="85" Title="[ProductName] Setup" NoMinimize="yes">
<Control Id="No" Type="PushButton" X="132" Y="57" Width="56" Height="17"
Default="yes" Cancel="yes" Text="No">
<Publish Event="EndDialog" Value="Exit">1</Publish>
</Control>
<Control Id="Yes" Type="PushButton" X="72" Y="57" Width="56" Height="17" Text="Yes">
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>
<Control Id="Text" Type="Text" X="48" Y="15" Width="194" Height="30">
<Text>A previous version of [ProductName] is currently installed. By continuing the installation this version will be uninstalled. Do you want to continue?</Text>
</Control>
</Dialog>
I use WiX 3.5. My installer should enable both per-user and per-machine installation. I would like to achieve that by using radio buttons ("Everyone" and "Just me").
I found a couple of references on the Internet:
Selecting current-user or all-users install: Adding a user interface, part of Yet Another WiX Tutorial - Part 2 - Adding the UI.
Set the ALLUSERS property to an empty string: Using WiX 3.0 to create a per-user MSI that does not prompt for elevation on Windows Vista
If I understand that correctly my installer should set ALLUSERS property to 1 for per-machine installation and to "" (empty string) for per-user installation.
My problem is no matter what I try ALLUSERS is always set to 1. Even when I don't set it at all!
Here is a couple of things I tried:
<Control Id="UserSelection"
Type="RadioButtonGroup"
X="26"
Y="115"
Width="305"
Height="45"
Property="ASSISTANCE_USERS"
Text="ASSISTANCE_USERS">
<RadioButtonGroup Property="ASSISTANCE_USERS">
<RadioButton Value="cur"
X="0"
Y="0"
Width="295"
Height="16"
Text="Just me" />
<RadioButton Value="all"
X="0"
Y="20"
Width="295"
Height="16"
Text="Everyone" />
</RadioButtonGroup>
</Control>
and then setting the ALLUSERS based on ASSISTANCE_USERS:
<Publish Property="ALLUSERS"
Value="{}">ASSISTANCE_USERS = "cur"</Publish> <!-- set null value -->
<Publish Property="ALLUSERS"
Value="1">ASSISTANCE_USERS = "all"</Publish>
However, ALLUSERS is always 1.
I also tried just setting ALLUSERS to an empty string:
<Property Id="ALLUSERS" Secure="yes"/>
This should set ALLUSERS to "", yet it stays "1"
Once I'm able to set ALLUSERS, I should be able to use HKMU for per-user and per-machine installtion.
Check a verbose log (using /l*vx): MSI logs every property change so you can see when ALLUSERS is being set.
My installer, created wth WiX is localized via .wxl files. It is possible in WiX to specify multiple cultures and light.exe will be called multiple times, creating an installer for each language (this is available while building installer from Visual Studio).
All works file except for EULA. It is defined in .wxs file via
<WixVariable Id='WixUILicenseRtf' Value='en.rtf' />
And i don't know a good way to change this value from .wxl localization file. Using
<WixVariable Id='WixUILicenseRtf' Value='!(loc.EulaFile)' />
<String Id='EulaFile'>en.rtf</String>
Is not working, sice .wxl files are used at link-time and .wxs is compiled before them, so compiler can't find !(loc.EulaFile). Searching forums i have found two workarounds. First is to create a custom license dialog for each language - it seems to work, but it's a very hard way and bloat source code a lot. Second way is to drop Visual Studio / Votive build and to call light.exe multiple times, specifying different license file each time via -d command-line key.
Is it any way to solve this problem and use localized EULA files so project can be built in VisualStudio + Voltive without a need to copy-paste lots of dialogs? Localizing installers is a very common problem, so maybe some solution exist that i don't know about?
There is another way to do this, and although it is a bit messy it is less messy than the two workarounds the OP has mentioned. And credit where credit is due, this answer is almost 100% based on this post http://weblogs.sqlteam.com/mladenp/archive/2010/04/15/WiX-3-Tutorial-Custom-EULA-License-and-MSI-localization.aspx by Mladen Prajdić.
The following is based on WiX 3.5.
You create a slightly modified copy of the LicenseAgreementDlg dialog and include it in your project.
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
The use and distribution terms for this software are covered by the
Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
which can be found in the file CPL.TXT at the root of this distribution.
By using this software in any fashion, you are agreeing to be bound by
the terms of this license.
You must not remove this notice, or any other, from this software.
-->
<!-- This is a modified version of LicenseAgreementDlg to support selection of localized versions of
the license file. It is very much based on this article:
http://sqlserverpedia.com/blog/sql-server-bloggers/wix-3-tutorial-custom-eula-license-and-msi-localization/ -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI>
<Dialog Id="LicenseAgreementKludge" Width="370" Height="270" Title="!(loc.LicenseAgreementDlg_Title)">
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.LicenseAgreementDlgBannerBitmap)" />
<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="340" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.LicenseAgreementDlgDescription)" />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.LicenseAgreementDlgTitle)" />
<Control Id="LicenseAcceptedCheckBox" Type="CheckBox" X="20" Y="207" Width="330" Height="18" CheckBoxValue="1" Property="LicenseAcceptedKludge" Text="!(loc.LicenseAgreementDlgLicenseAcceptedCheckBox)" />
<Control Id="Print" Type="PushButton" X="112" Y="243" Width="56" Height="17" Text="!(loc.WixUIPrint)">
<Publish Event="DoAction" Value="WixUIPrintEula">1</Publish>
</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)">
<Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">!(wix.WixUICostingPopupOptOut) OR CostingComplete = 1</Publish>
<Condition Action="disable"><![CDATA[LicenseAcceptedKludge <> "1"]]></Condition>
<Condition Action="enable">LicenseAcceptedKludge = "1"</Condition>
</Control>
<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>
<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="140" Sunken="yes" TabSkip="no">
<Text SourceFile="$(var.ProjectDir)\!(loc.LicenseRtf)" /> <!-- this value has been modified -->
</Control>
</Dialog>
</UI>
</Fragment>
</Wix>
In your main WiX source file you add the following code to "patch" your new dialog into the dialog sequencing instead of the original one:
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementKludge">1</Publish>
<Publish Dialog="LicenseAgreementKludge" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
<Publish Dialog="LicenseAgreementKludge" Control="Next" Event="NewDialog" Value="InstallDirDlg">LicenseAcceptedKludge = "1"</Publish>
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementKludge">1</Publish>
Note that this is based on using the WixUI_InstallDir dialog collection - for other collections, such as WixUI_Mondo, you will probably have to modify the above by looking at the source.
Finally, in each of your localization files you place one line like this:
<String Id="LicenseRtf">en-us\MerliniaSMSGatewayLicense.en-us.rtf</String>
<String Id="LicenseRtf">da-dk\MerliniaSMSGatewayLicense.da-dk.rtf</String>
And, of course, you place the localized license file as indicated. I'm placing the license files (and localization files) in subfolders, but this is not necessary.
Like I said, it's a bit messy, but it does work.
Best solution is the simplest, just use the WixUILicenseRtf variable on the command line when specifying your .wxl file.
light -loc setup_fr-FR.wxl -dWixUILicenseRtf=EULA_fr-FR.rtf ...
Refer User Interface Basics at WiX Wiki for more information.
Localizing the EULA is very simple. Add a ScrollableText Control to one of your dialogs. Reference a localization String in the text element of the ScrollableText Control.
<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="140" Sunken="yes" TabSkip="no">
<Text>!(loc.License)</Text>
</Control>
Next create a localization file, say for american english. Name the file en-US.wxl. Create a localization String element in the localization file which uses the identifier referenced in the Text element of the ScrollableText Control, in this case it's called License. Add the raw rtf string of your EULA as a CDATA element of the localization string.
To get the raw data, create an rtf file with wordpad, for example. Open that rtf file with notepad and copy its content. Paste that content into the CDATA element of the localization String element. Be sure to omit all whitespace between the String and CDATA Tags.
An example localized String element follows:
<String Id="License"><![CDATA[{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\sa200\sl276\slmult1\lang7\f0\fs22 American EULA.}]]></String>
So the key to including multiple EULA's is to use the raw rtf data in the respective localization files.
Go to Solution's Configuration Manager, on the installer project line create a new configuration for each localization you want to use, like the following for example:
Now, on the installer project properties page / Build, for each created configuration, set a single culture on "Cultures to build" and set a different value on "Define variables" box each culture:
For instance, for es-ES:
WixUILicenseRtf=.\Assets\license-es-ES.rtf
For en-US:
WixUILicenseRtf=.\Assets\license-en-US.rtf
... etc
To build your installers:
For each culture:
Go to the configuration manager,
Select the configuration culture for the installer, accept
Build
Pros:
No need to deal with custom actions, custom dialogs or console commands
Only need to config it once. Making it run is a mechanic task
Cons:
Needs some extra clicks for each build
Messy with more than three cultures