Major Upgrade in WiX installer not working following a UIRef change - visual-studio

I have changed a UIRef tag between versions of my deployment.
from Version 1.0: <UIRef ID="WixUI_FeatureTree" />
to Version 2.0: <UIRef ID="WixUI_Advanced" />
Wix Version 3.6
Now, when I run the Version 2.0 installer, it does not detect
the previous version, so instead of uninstalling during the upgrade
it installs a new version next to the existing version.
Intermediate versions upgraded fine (1.0->1.1->1.2).
The major changes in 2.0 are:
A new sub-feature under the main
Change to the UIRef from WixUI_FeatureTree, to WixUI_Advanced
to allow deployment to select from 'AllUsers' and 'Single User'
Remove Existing Products is defined as:
<InstallExecuteSequence>
<RemoveExistingProducts After='InstallInitialize' />
<Custom Action=...
...
My product is defined as:
#UpgradeCode# is consistent between versions
#ProductId# is changed between versions
<Product Id="#ProductId"
UpgradeCode="#UpgradeCode#"
Name="!(loc.ApplicationName)"
Language="1033"
Codepage="1252"
Version="2.0.0"
Manufacturer="!(loc.Manufacturer)">
<Package
Id="*"
InstallerVersion="300"
InstallPrivileges="elevated"
Languages="1033"
Compressed="yes"
InstallScope="perMachine"
Manufacturer="!(loc.Manufacturer)"
SummaryCodepage="1252"
Platform="x86"
Description="!(loc.ApplicationName)"/>
<Upgrade Id="#UpgradeCode#">
<UpgradeVersion OnlyDetect="no" Property="PREVIOUSFOUND"
Minimum="1.0.0" IncludeMinimum="yes"
Maximum="2.0.0" IncludeMaximum="no"/>
</Upgrade>
I am wondering if there is something that I can do
to force the installer to check the upgrade and perform
remove of previous version that is no longer being handled
following my changes.

In the build log I noticed:
MSI (c) (6C:C4) [12:04:44:624]: FindRelatedProducts: current install is per-user. Related install for product '{PRODUCT-GUID }' is per-machine. Skipping...
Action ended 12:04:44: FindRelatedProducts. Return value 1.
I had removed:
<Product ... InstallScope="perMachine" ... />
when upgrading versions.
I did not realize that upgrade matching included the InstallScope Property of Product.
I can still install per-user using <UIRef Id="WixUI_Advanced" />, so this property does not seem to affect the selection of PerMachine or PerUser, so I have put it back in. Upgrade now works again.

Related

MsiPackage conditional install: Don't uninstall if it detects package is already installed

I'm using Wix Bootstrapper and want to install a few applications through .msi packages alongside my main application. These applications may be installed in the target PC already so I need to detect these first and skip installation if they are already installed. Furthermore, during uninstallation, these applications should not be uninstalled since the Wix Bootstrapper did not install them.
I've tried to use the InstallCondition attribute but (as expected) it uninstalls if it detects the application is already installed.
My Bundle.wxs looks like this:
...
<Bundle>
<util:FileSearch Id='CheckApplicationX' Path='[ProgramFilesFolder]ApplicationX\ApplicationX.exe' Variable='ApplicationXFile' Result='exists' />
<Chain DisableRollback="yes">
...
<MsiPackage Id="InstallApplicationX" Vital="yes" Compressed="yes" DisplayInternalUI="no" EnableFeatureSelection="no" SourceFile="..\application-x.msi" Name="Application X" DisplayName="Application X" ForcePerMachine="yes" InstallCondition="NOT ApplicationXFile" />
...
</Chain>
</Bundle>
...
Any help/hints are appreciated!
You can try to detect if the applications are installed by looking in the Windows Registry and try to identify if there are "traces" left by those applications.
You can use the RegistrySearch tag to perform a conditional evaluation of the registry entries you're looking for and then deny the installation.
There's an example on Wix Website available at this link.
The following example shows how you can define if .NET 2.0 is installed on the target machine
<Property Id="NETFRAMEWORK20">
<RegistrySearch Id="NetFramework20"
Root="HKLM"
Key="Software\Microsoft\NET Framework Setup\NDP\v2.0.50727"
Name="Install"
Type="raw" />
</Property>
<Condition Message="This application requires .NET Framework 2.0. Please install the .NET Framework then run this installer again.">
<![CDATA[Installed OR NETFRAMEWORK20]]>
</Condition>

how to give optional install for multiple msi packages in single WiX installer?

I have multiple packages that I want to install using single installer. Two of them are MSI packages, other two are exe files. I am using WiX to make single installer to install all four packages, and want to give user option to choose which one (or more) they want to install.
Here, One MSI package is for WPF Desktop application that I am developing, other 3 packages are add-on features that I want to give option to select/deselect.
So, far I am able to install all four of them using WiX BootStrapper. But I could not find how to give select options to user during installation.
Also I am using Visual Studio 2019 IDE for development.
Assuming your using the standard bootstrapper application you need to bring in a copy of your favorite Theme.wxl:
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense" >
<bal:WixStandardBootstrapperApplication LicenseFile="Resources\EULA.rtf" LogoFile="Resources\Icon.png" LicenseUrl="http://www.google.com" LocalizationFile="Resources\HyperlinkTheme.wxl" ThemeFile="Resources\HyperlinkTheme.xml" SuppressOptionsUI="yes" />
</BootstrapperApplicationRef>
Then in the Theme wxs add a button:
<Text X="11" Y="175" Width="130" Height="20" FontId="3" Visible="yes" DisablePrefix="yes">Install Something</Text>
<Checkbox Name="INSTALLSOMETHING" X="140" Y="175" Width="-11" Height="20" TabStop="yes" FontId="3" Visible="yes"></Checkbox>
Then in your bundle.wxs declare a variable so it can be passed as an argument for silent installations:
<Variable Name="INSTALLSOMETHING" bal:Overridable="yes" Type="string" Value="" />
And finally use it's value to control the installation of something.
<ExePackage Id="Something" SourceFile="Something.exe" InstallCondition="(INSTALLSOMETHING="1") or (INSTALLSOMETHING="True")" />
Rinse and repeat 3 more times.

Why doesn't a WIX major upgrade update all of my files?

I've just taken over a complicated Visual Studio/WiX project (I've never used WiX) and all of a sudden upgrades no longer include all of the files.
We don't version every .dll so we need to do every upgrade as a Major Upgrade. (I know this isn't usually a good idea, but this is for an appliance that only gets upgraded by a script on a USB drive). I've read this article and made the following changes:
I changed the Product Id from a Guid to an '*' in the Product.wxs file
I added <MajorUpgrade Schedule="afterInstallFinalize" DowngradeErrorMessage="A newer version of [ProductName] is already installed."/> to the Product.wxs file (I've also tried Schedule=afterInstallExecute) with no luck.
I added the following block of code to the Product.wxs file:
<Upgrade Id='291EF866-D9B7-4103-B006-F11E50EEDC7B'> <UpgradeVersion
OnlyDetect='no' Property='PREVIOUSFOUND' Minimum='1.0.0'
IncludeMinimum='yes' Maximum='99.0.0' IncludeMaximum='no' />
</Upgrade>
So when I started this process some of the .dlls were updating and others weren't. Now most update, but not all. Here's a sample line from the log for one of the files that's not updating:
MSI (s) (34:AC) [16:56:06:306]: Component: cmp9EE90E3731EB7F54B1D4B6D421BF1286; Installed: Absent; Request: Local; Action: Local
And here's the second line that refers to that file:
MSI (s) (34:98) [16:56:08:583]: Component: cmp9EE90E3731EB7F54B1D4B6D421BF1286; Installed: Local; Request: Absent; Action: Null
You need to change Schedule to afterInstallInitialize in the MajorUpgrade
element.
Schedule="afterInstallInitialize"
And remove the Upgrade element.
You can check the specifics in this tutorial.
And I suggest you to read about the Schedule attribute from Here.
I finally got it to work with an obscure property called REINSTALLMODE and setting it's Value to amus. Thanks Hannes for this post!!
Here's the solution:
<Property Id="REINSTALLMODE" Value="amus" />
<Upgrade Id='291EF866-D9B7-4103-B006-F11E50EEDC7B'>
<UpgradeVersion OnlyDetect='no' Property='PREVIOUSFOUND'
Minimum='1.0.0' IncludeMinimum='yes'
Maximum='99.0.0' IncludeMaximum='no' />
</Upgrade>

How Does one install a shortcut to a nested sub-directory using WiX

This is a repeat of Wix - Keeping track of installed applications, but the accepted answer just suggested that one could do something different than what was asked.
So, (in WiX) how does one make Per Machine installers for separate products from a single company with each having shortcuts under Start Menu/Programs/CompanyName/ProductName (where ProductName changes for each product) such that Start Menu/Programs/CompanyName will be removed if and only if all the products are uninstalled?
The specific names don't matter, but for discussion assume CompanyName is ExampleLLC with products named ProductA, ProductB, and ProductC. Assuming each product has a separate installer and the shortcuts are each to a file installed by the same product installer. So, call them RunA, RunB, and RunC targeted at ProductA.exe, ProductB.exe, and ProductC.exe respectively.
To be clear "Start Menu/Programs" maps to "C:\Users\All Users\Microsoft\Windows\Start Menu\Programs" under Windows 7, but other OS versions map this differently.
NOTE: The answer must work for perMachine installations and if ICE warnings must be ignored, please mention them.
This sounds trivial, but WiX and the Installer SDK emit errors or warnings at everything I've tried. They need a "key" to check if something (or collection thereof) is still present on the machine and have biases against both directories and shortcuts as keys. AND they put special requirements on items installed per user, but then don't trust that "ProgramMenuFolder" is NOT per user for a "perMachine" installation.
Just include the same component (with the same GUID), which installs the shortcut, into two products. MSI will count and handle installed component by itself.
Ignore ICE64 (i.e. tell light.exe to do so) and "just do it".
But use advertised shortcuts or see the question Wix create non advertised shortcut for all users / per machine.
If you do those two things the extra nesting level for "CompanyName" won't matter.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="ProductA" Language="1033" Version="1.0.0.0" Manufacturer="ExampleLLC" UpgradeCode="YOUR_GUID_HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="Setup.cab" EmbedCab="yes" CompressionLevel="high" />
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramMenuFolder">
<Directory Id="MyStartMenuCompanyFolder" Name="ExampleLLC">
<Directory Id="MyStartMenuProductFolder" Name="ProductA" />
</Directory>
</Directory>
<Directory Id="ProgramFilesFolder">
<Directory Id="MyProgramFilesCompanyFolder" Name="ExampleLLC">
<Directory Id="MyProgramFilesProductFolder" Name="ProductA">
<Component Id="ProductA.exe">
<File Source="../ProductA/bin/$(var.Configuration)/ProductA.exe" KeyPath="yes">
<Shortcut Id="RunA" Name="RunA" Directory="MyStartMenuProductFolder" Advertise="yes"/>
</File>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Feature Id="Complete" Level="1">
<ComponentRef Id="ProductA.exe" />
</Feature>
</Product>
</Wix>
Produces 2 instances of ICE error 64 complaining that each directory (MyStartMenuProductFolder and MyStartMenuCompanyFolder) "is in the user profile but is not listed in the RemoveFile table".
If one makes a duplicate WiX file substituting ProductB for ProductA (and RunB for RunA), then ignoring this error produces installers that do just what they should.
So don't trust ICE64's implication that something won't get removed on uninstall. Ignore the error and just test your installer.
NOTE: This error has nothing to do with having an extra directory level, but in trying to dodge it AND fighting with ICE43 and ICE57 that pop up if you try to use a non-advertised shortcut led me "down a rabbit hole" involving using the inner directory (MyStartMenuProductFolder) as a KeyPath for a component including just the RunA shortcut. Which worked fine, but left the ICE64 warning for the outer directory (MyStartMenuCompanyFolder).

WIX public properties displayed on the UI

We have an installer created using WIX. As part of this install we would like to show the currently selected installation path. I thought this would be much easier than it is, apparently. I have tried using the a public property "INSTALLDIR" (I know we're not using Installshield, this value is a directory ID.)
<Directory Id="INSTALLDIR" Name="AcmeInc">
I can also see where INSTALLDIR gets set when running the install
MSI(EC:6C) Dir (target): Key: INSTALLDIR , Object: C:\Program Files\AcmeInc\
but when I try to show this on the UI using a Text attribute I get "...\." which doesn't even look to be a relative path.
I know there has got to be something simple I'm missing here.
Assuming you're using WiX 3.5 and the MajorUpgrade element - the following should work (I usually use APPLICATIONFOLDER instead of INSTALLDIR - but they should be interchangeable).
First, let's set ARPINSTALLOCATION as described on http://robmensching.com/blog/posts/2011/1/14/ARPINSTALLLOCATION-and-how-to-set-it-with-the-WiX-toolset
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize" />
Now lets set the selected installation folder to the previous installation folder, if one previously existed that is.
<Property Id="INSTALLDIR" Secure="yes">
<RegistrySearch Id="FindInstallLocation"
Root="HKLM"
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[WIX_UPGRADE_DETECTED]"
Name="InstallLocation"
Type="raw"
Win64="yes" />
</Property>
And during the UI sequence, we want this value to be set 'early'
<InstallUISequence>
<AppSearch After="FindRelatedProducts"/>
</InstallUISequence>

Resources