Wix Installer to upgrade and remove files + registry entries - wix

I have an application that needs 1. to create DLL files in a Program Files subfolder (e.g. C:\Program Files (x86)\myapp), and 2. to create a registry entry in HKCU. When I run the Remove, I need this subfolder and its files to be deleted, as well as the registry entry.
When I run the installation file of a newer version, I need the new DLL files to replace the existing ones.
I've been struggling getting it to work, having tried several tips from various threads and sites.
So far I get the Program Files to be removed but not the Registry. And I cannot get the file upgrade to work (I change the UpgradeCode & ProductVersion for each new release)
Here is an extract of what I have
<Product Id="$(var.ProductID)"
Name="myapp"
Language="1033"
Version="$(var.ProductVersion)"
UpgradeCode="$(var.UpgradeCode)"
Manufacturer="$(var.Manufacturer)">
<Package Description="Windows installer for myApp $(var.ProductVersion)"
Comments="Execute to install myApp $(var.ProductVersion)"
InstallerVersion="200"
Compressed="yes" />
<Media Id="1" Cabinet="contents.cab" EmbedCab="yes" CompressionLevel="high"/>
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="$(var.ProductVersion)"
OnlyDetect="yes"
Property="NEWERVERSIONDETECTED" />
<UpgradeVersion Minimum="1.0.0.0"
IncludeMinimum="yes"
Maximum="$(var.ProductVersion)"
IncludeMaximum="no"
Property="OLDERVERSIONBEINGUPGRADED" />
</Upgrade>
<CustomAction Id="UIandAdvertised" Error="Something about the UI."/>
<Directory Id="TARGETDIR" Name="SourceDir"/>
<Feature Id="Complete"
Title="myApp"
Description="Installation of myApp $(var.ProductVersion)"
Level="1">
<ComponentRef Id="myAppFiles"/>
<ComponentRef Id="RegistryEntry"/>
</Feature>
<Property Id="WIXUI_INSTALLDIR">INSTALLDIR</Property>
<UIRef Id="WixUI_InstallDir"/>
<InstallExecuteSequence>
<RemoveExistingProducts Before="InstallInitialize" />
<RemoveRegistryValues />
</InstallExecuteSequence>
</Product>
My files and reg infos are maintained in a separate file:
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="INSTALLDIR" Name="myapp">
<Component Id="myAppFiles" Guid="{xxxx-xxxx-xxxx-xxxx-xxxxxxxx}">
<File Id="myapp.dll" Name="myapp.dll" KeyPath="yes" Source="..\src\bin\x86\Release\myapp.dll" />
</Component>
<Component Id="RegistryEntry" Guid="{xxxxxxx-xxxx-xxxx-xxxx-xxxxxxx}" Win64="no" >
<RegistryKey Root="HKCU" Key="Software\myapp" Action="createAndRemoveOnUninstall">
<RegistryValue Type="string" Value="myapp" />
</RegistryKey>
</Component>
</Directory>
</Directory>
</DirectoryRef>
Any help will be highly appreciated.

Use Product ID ="*",
It changes product id guid for each build.
But keep upgrade code same for product, unless you dont want to support upgrade.
You can use major upgrade tag instead of Upgrade tag. It is easier to use.
<MajorUpgrade AllowDowngrades="no"
AllowSameVersionUpgrades="no"
Schedule="afterInstallValidate"
DowngradeErrorMessage="Newer version of [ProductName] is already installed."/>

Related

WiX Installer use RegistrySearch result for directory

I'm trying to create an installer using WiX for an add-in to a product called SolidWorks.
Looking at the docs led me to believe that I should be able to look up a location based on a registry value to find the install destination.
Here is the registry value I'm trying to target:
As seen in the picture it is located at HKEY_LOCAL_MACHINE\SOFTWARE\SolidWorks\SOLIDWORKS 2022\Setup\SolidWorks Folder.
I've tried to follow the instructions and have tried many iterations, with the following being the latest.
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="SolidWorks Add-In" Language="1033" Version="1.0.0.0" Manufacturer="My Company" UpgradeCode="073e3b99-1977-4a3e-a4dc-0d61cc6ddbee">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Description="SolidWorks Add-In Installer" Manufacturer="My Company" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<Feature Id="ProductFeature" Title="Installer" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Property Id="MsiLogging" Value="v" />
<Property Id="SOLIDWORKSDIR">
<RegistrySearch Id="SolidWorksRegistry" Type="raw" Root="HKLM" Key="SOFTWARE\SolidWorks\SOLIDWORKS 2022\Setup" Name="SolidWorks Folder" />
</Property>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="SOLIDWORKSDIR" Name=".">
<Directory Id="My_Company" Name="My Company">
<Directory Id="INSTALLFOLDER" Name="SolidWorks Add-In" />
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="AutofacLibrary" Guid="3124c97d-079d-48fe-bc7c-e594bf49ae4a">
<File Id="AutofacDLL" Name="Autofac.dll" DiskId="1" Source="..\SolidWorksAddIn\bin\Release\Autofac.dll" KeyPath="yes" />
<File Id="AutofacPDB" Name="Autofac.pdb" DiskId="1" Source="..\SolidWorksAddIn\bin\Release\Autofac.pdb" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
This seems to completely ignore the registry value though and the install location is C:\My Company\SolidWorks Add-In
I can't figure out what needs to change. How am I targeting the registry value incorrectly or referencing the property incorrectly that isn't allowing the installer to place the installed files in the directory I want them to be in?
As per the comments above, the issue is that the registry key is in the 64-bit hive but the package was 32-bit. The fix is to either make the package 64-bit (so the searches look in 64-bit locations by default) or make the registry search 64-bit by adding the Win64='yes' attribute.

wix 3.8 silent install - ui level 2

I want to create a WIX Installer (3.8) that only installs silently.
I'm using the Wix file attached to demonstrate my issue.
At
UILevel=2
<InstallExecuteSequence>
<FindRelatedProducts Before="LaunchConditions">UILevel=2</FindRelatedProducts>
</InstallExecuteSequence>
I'm setting the UI level to 2
According to:
msdn.microsoft.com/en-us/library/aa372096%28v=vs.85%29.aspx
then it's:
"
INSTALLUILEVEL_NONE 2 Completely silent installation.
"
So far so good. I can install the "product" which is nothing but an empty directory.
When I set the product's version to: Version="1.1.0.0" and want to do a major upgrade everything also works fine.
When I look at the program an feature "tool" from Microsoft
as shown here:
http://windows.microsoft.com/en-us/windows/uninstall-change-program#uninstall-change-program=windows-7
I see both versions (version 1.0.0.0 and 1.1.0.0) which is not what I expected the Wix installer should do.
When I remove
<InstallUISequence>
<FindRelatedProducts Before="LaunchConditions">UILevel=2</FindRelatedProducts>
</InstallUISequence>
<InstallExecuteSequence>
<FindRelatedProducts Before="LaunchConditions">UILevel=2</FindRelatedProducts>
</InstallExecuteSequence>
from the Wix script, install Version 1.0.0.0 and later after changing the wix script to 1.1.0.0
and major upgrading again,
I only see 1 version (1.1.0.0) at the program an feature "tool" from Microsoft
( windows.microsoft.com/en-us/windows/uninstall-change-program#uninstall-change-program=windows-7 )
which is what I expect the windows installer should do.
So my question would be:
What is missing or wrong at the script
( that the program an feature "tool" from Microsoft shows 2 Versions after a major upgrade )
Wix script:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="SetupProject1" Language="1033" Version="1.1.0.0" Manufacturer="asdf" UpgradeCode="BE170BF6-0C06-4A50-B81B-CDF6609FAD5A">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perUser" InstallPrivileges="limited" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallInitialize" />
<MediaTemplate />
<InstallUISequence>
<FindRelatedProducts Before="LaunchConditions">UILevel=2</FindRelatedProducts>
</InstallUISequence>
<InstallExecuteSequence>
<FindRelatedProducts Before="LaunchConditions">UILevel=2</FindRelatedProducts>
</InstallExecuteSequence>
<Feature Id="ProductFeature" Title="SetupProject1" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder">
<Directory Id="INSTALLFOLDER" Name="SetupProject1" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="test" Guid="D6527568-4C76-493B-AF1F-9E973723E773"
SharedDllRefCount="no" KeyPath="no" NeverOverwrite="no" Permanent="no" Transitive="no"
Win64="no" Location="either">
<CreateFolder/>
<RemoveFolder Id="ProductComponents" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\MyFantasyCompany\MyApplicationName" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
First, there's no such thing as WiX script. WiX is not a imperative programming language, it's a declarative language.
Your major upgrade is failing because the condition on FindRelatedProducts is evaluating to false which means it can never detect the ProductCode of the previous MSI and remove it as part of the upgrade.
If you really want a silent install only, why not just omit a UI from the installer? Personally I have no idea why you are trying to do this and it doesn't follow established best practices.

Wix how to hide feature options (no subfeatures)

There is a similar question
Edit context menu (selectiontree) in customize dialog?
but the link in the accepted answer states:
"You cannot remove Entire feature will be installed on local hard drive from the options. It is displayed only when there are subfeatures and enables installation of the subfeatures as well as the feature itself as opposed from Will be installed on local hard drive which installs only the selected features and does not affect subfeatures."
However, I have no subfeatures. How to remove the Entire feature... option?
Here's the code below:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WixTestFeatureTree" Language="1033" Version="1.0.0.0" Manufacturer="TestManufacturer" UpgradeCode="bb04a635-6251-4fd5-8d2f-182d3441dc0a">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<UIRef Id="WixUI_FeatureTree" />
<UIRef Id="WixUI_ErrorProgressText" />
<Feature Id="ExeFeature" Title="The EXE file" Level="1">
<Component Id="TheApp" Guid="*" Directory="INSTALLFOLDER">
<File Id="TestExe" Source="Test.exe" Vital="yes"></File>
</Component>
</Feature>
<Feature Id="PdfFeature" Title="The PDF file" Level="1">
<Component Id="ThePDF" Guid="*" Directory="INSTALLFOLDER">
<File Id="TestPDF" Source="Test.pdf" Vital="yes"></File>
</Component>
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WixTestFeatureTree" />
</Directory>
</Directory>
</Fragment>
</Wix>
It looks Windows Installer always displays Entire feature will be installed on local hard drive item even if there are no subfeatures. At least this item was present in all the cases that I tested where there were no visible subfeatures. It could also depend on the version of Windows Installer, I tested in Windows 7 with all the latest updates.
I've always thought Windows Installer doesn't display Entire feature will be installed on local hard drive item for a feature which has no subfeatures. Latest tests proved I was wrong.
You need to add the UI type in order to have a different UI in the installer.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WixTestFeatureTree" Language="1033" Version="1.0.0.0" Manufacturer="TestManufacturer" UpgradeCode="bb04a635-6251-4fd5-8d2f-182d3441dc0a">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<UI Id="MyWixUI_FeatureTree">
<UIRef Id="WixUI_FeatureTree" />
</UI>
<UIRef Id="WixUI_ErrorProgressText" />
<Feature Id="ExeFeature" Title="The EXE file" Level="1">
<Component Id="TheApp" Guid="*" Directory="INSTALLFOLDER">
<File Id="TestExe" Source="Test.exe" Vital="yes"></File>
</Component>
</Feature>
<Feature Id="PdfFeature" Title="The PDF file" Level="1">
<Component Id="ThePDF" Guid="*" Directory="INSTALLFOLDER">
<File Id="TestPDF" Source="Test.pdf" Vital="yes"></File>
</Component>
</Feature>
<UIRef Id="WixUI_Mondo"></UIRef>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WixTestFeatureTree" />
</Directory>
</Directory>
</Fragment>
</Wix>
add <UIRef Id="WixUI_Mondo"></UIRef> , also add reference to WixUIExtension.dll
each feature has **Level**attribute, level=1 meaning the feature will be installed, if you change the level for 1000 for example the user can pick in the custom dialog weather he wants to install this feature or not

Get WiX / MSI to install some registry always, preserve some pre-existing ones

I have a WiX installation that also needs to write some registry keys, and I was wondering if there's a way to tell WiX/MSI to
only create a key if it doesn't exist yet
always create/overwrite another key, even if it exists
I tried something like this:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="TestRegistry" Language="1033" Version="1.0.2"
Manufacturer="Myself" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes"
InstallScope="perUser" InstallPrivileges="limited" />
<MajorUpgrade DowngradeErrorMessage="A newer version installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="TestRegistry" Level="1">
<ComponentRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="dirManufacturer" Name="Manufacturer">
<Directory Id="INSTALLFOLDER" Name="TheProduct">
<Component Id="ProductComponents" Guid="*" DiskId="1">
<RegistryKey Root="HKCU" Key="Software\Manufacturer\TheProduct"
Action="createAndRemoveOnUninstall">
<RegistryValue Type="string" Name="Install Directory"
Value="[INSTALLFOLDER]" KeyPath="yes" />
<RegistryValue Type="string" Name="Product Version"
Value="[ProductVersion]" />
<RegistryValue Type="string" Name="Default Language" Value="en" />
<RegistryValue Type="string" Name="Web Site URL"
Value="https://product.manufacturer.info/" />
</RegistryKey>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
</Wix>
and here, I'd like to always overwrite the Install Directory and Product Version keys with current values, but I would like to preserve other settings, like Default Language.
Is there any way to do this?
Right now, when I install 1.0.0 fresh on a new system, it creates the registry keys alright. When I uninstall it, they're gone - so far, so good.
But when I installed v1.0.1 and then - without uninstalling v1.0.1 - installed v1.0.2 on top of this, ALL the defined registry keys were updated and contained the default values defined in the WiX script - the changes I had made manually were wiped out.
You will need to break the registry values out to there own components and set the NeverOverwrite attribute on them
<Component Id="DefaultLangaugeComponent" Guid="*" NeverOverwrite="yes">
<RegistryKey Root="HKCU" Key="Software\Manufacturer\TheProduct"
Action="createAndRemoveOnUninstall">
<RegistryValue Type="string" Name="Default Language" Value="en" />
</RegistryKey>
</Component>

WIX Installer upgrade

I am trying to create an MSI using WIX and I seem to have stumbled across a small issue that is confusing me a bit in regards to the upgrade. I have followed about 3 tutorials on the subject and each one gives me the same result. When I try to upgrade the application I get a generic
Another version of this product is already installed.
message. After looking around I saw that in order to successfully upgrade I need to specify a new Product GUID. This seemed odd to me because the main WiX website said that that is only needed for major installs. Since I wasn't getting much luck I decided to go with it. Lo and behold it successfully executed the installer, but when I checked in Add/Remove Programs I now had 2 copies of the application installed. This is driving me crazy. Please see the below .wxs and please show me my errors where applicable.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="PRODUCT-GUID-GOES-HERE-B86BCC79EEFD" Name="Sample Application" Language="1033" Version="$(var.ProductVersion)" Manufacturer="Sample Inc." UpgradeCode="$(var.UpgradeCode)">
<Package Id="*" Keywords="Installer" Platform="x64" InstallerVersion="200" InstallPrivileges="elevated" InstallScope="perMachine" Compressed="yes" />
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="$(var.ProductVersion)" IncludeMinimum="no" OnlyDetect="yes" Language="1033" Property="NEWPRODUCTFOUND" />
<UpgradeVersion Minimum="$(var.RTMProductVersion)" IncludeMinimum="no" Maximum="$(var.ProductVersion)" IncludeMaximum="no" Language="1033" Property="UPGRADEFOUND" />
</Upgrade>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="Sample" Name="Sample">
<Directory Id="INSTALLLOCATION" Name="Sample Application">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<Component Id="SampleApplication" Guid="APPLICATION-GUID-GOES-HERE-c7247f5d1b42" Win64="yes">
<!-- TODO: Insert files, registry keys, and other resources here. -->
<File Id="SampleEXE" Name="Sample.exe" Source="Sample.exe" ProcessorArchitecture="x64" KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Feature Id="Complete" Title="sample64" Level="1">
<!-- TODO: Remove the comments around this ComponentRef element and the Component above in order to add resources to this installer. -->
<ComponentRef Id="SampleApplication" />
<!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
<ComponentGroupRef Id="Product.Generated" />
</Feature>
<CustomAction Id="NoDowngrade" Error="A later version of [ProductName] is already installed." />
<InstallExecuteSequence>
<Custom Action="NoDowngrade" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
<RemoveExistingProducts After="InstallFinalize" />
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="NoDowngrade" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
</InstallUISequence>
</Product>
</Wix>
Thanks in advance for any help.
Set Product/#Id to "*" to get automatic product code changes and use the MajorUpgrade element. For more context, see my blog.