Understanding PackageCode, ProductCode and UpgradeCode of WIX with multi instances - wix

My multi instance msi setup work only if I use the same msi file. Then the user
can change the directory
install a new instance if it a new directory
update the instance if it an existing directory
every instance has its own uninstaller entry
If I use a new build of the setup and run an update then
a second uninstaller with the same display name is registered
A second of the new setup start in the maintenance mode. There is no
directory selection possible. An update of the other instances is
not possible.
After reading follow blog entry
http://blogs.msdn.com/b/pusu/archive/2009/06/10/understanding-msi.aspx
I have hard codes the PackageCode, ProductCode (per instance) and
UpgradeCode. And it work like expected. But I receive a big warning on
building. Can I ignore this? Is this the right solution?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" Language="1033" Manufacturer="i-net software GmbH" Name="i-net Test"
UpgradeCode="02c7fa01-5143-38ed-b923-2c2aaff301ae" Version="8.0.0.507">
<Package Comments="i-net Test Server" Compressed="yes" Id="c748d2f0-9ca5-3cbc-be9a-730c6d621f00"
InstallScope="perUser" />
<Media Cabinet="media1.cab" EmbedCab="yes" Id="1" />
<InstanceTransforms Property="INSTANCE_ID">
<Instance Id="Instance_0" ProductCode="c748d2f0-9ca5-3cbc-be9a-730c6d621f00" UpgradeCode="c748d2f0-9ca5-3cbc-be9a-730c6d621ff3" />
<Instance Id="Instance_1" ProductCode="c748d2f0-9ca5-3cbc-be9a-730c6d621f01" UpgradeCode="4c8e1670-9d04-3dce-b88a-1a4dbbbc976d" />
<Instance Id="Instance_2" ProductCode="c748d2f0-9ca5-3cbc-be9a-730c6d621f02" UpgradeCode="b76f160d-9395-3eda-a13d-d0566379ca8f" />
</InstanceTransforms>
<MajorUpgrade AllowDowngrades="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="i-net Test" />
</Directory>
</Directory>
<DirectoryRef Id="INSTALLDIR">
<Directory Id="Server" Name="Server">
<Component Guid="d62d7bcb-9242-39da-a43a-015df0f965af" Id="Server_Comp" MultiInstance="yes">
<CreateFolder />
<File Id="Server_testBuilds.jar" Name="testBuilds.jar" Source="..\testBuilds.jar" />
</Component>
</Directory>
<Component Guid="1543477d-59fc-3ec3-bb67-a541abd9cfba" Id="instance_path" MultiInstance="yes">
<RegistryKey ForceDeleteOnUninstall="yes" Id="instance_path_reg"
Key="Software\i-net software GmbH\i-net Test\Instances\[INSTANCE_NUMBER]" Root="HKLM">
<RegistryValue Type="string" Value="[INSTALLDIR]" />
</RegistryKey>
</Component>
</DirectoryRef>
<Property Id="INSTANCE_ID" Value="NotSet" />
<Property Id="InstancesCount" Value="3" />
<CustomAction Id="SetInstanceID" Script="vbscript">...</CustomAction>
<InstallUISequence>
<Custom Action="SetInstanceID" Before="ExecuteAction" />
<Custom Action="SetTransforms" After="SetInstanceID">ACTION = "INSTALL"</Custom>
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="SetInstanceID" Before="ValidateProductID" />
<Custom Action="SetProductName" After="SetInstanceID">PRODUCT_NAME</Custom>
</InstallExecuteSequence>
<CustomAction Id="SetTransforms" Property="TRANSFORMS" Value="{:[INSTANCE_ID];}[TRANSFORMS]" />
<CustomAction Id="SetProductName" Property="ProductName" Value="[PRODUCT_NAME]" />
<Feature Id="MainApplication">
<ComponentRef Id="Server_Comp" />
<ComponentRef Id="instance_path" />
</Feature>
</Product>
</Wix>
The SetInstanceID action can you find at https://github.com/i-net-software/SetupBuilder/blob/master/src/com/inet/gradle/setup/msi/MultiInstance.vbs
Before I have use "*" for the ProductCode (global and per instance) and
have hard coded only the UpgradeCode (global and per instance).

The solution was wrong. The PackageCode and ProductCode must be change for every build. Else the update does not work right. This is valid for a single instance but also for multiple instances msi files.
The problem with multiple instances is that the MajorUpgrade element does not work with multiple instances. If you inspect the resulting msi file with Orca you see only one entry with the UpgradeCode from the Product Element. The UpgradeCodes from your instances are not listen in this table. To solve this you must add the UpgradeCodes manually to this table:
<Property Id="InstancesCount" Value="3"/>
<InstanceTransforms Property="INSTANCE_ID">
<Instance Id="Instance_0" ProductCode="*" UpgradeCode="GUID_0"/>
<Instance Id="Instance_1" ProductCode="*" UpgradeCode="GUID_1"/>
<Instance Id="Instance_2" ProductCode="*" UpgradeCode="GUID_2"/>
</InstanceTransforms>
<Upgrade Id="GUID_0">
<UpgradeVersion MigrateFeatures="yes" Minimum="0.0.0.0" Property="WIX_UPGRADE_DETECTED_0"/>
</Upgrade>
<Upgrade Id="GUID_1">
<UpgradeVersion MigrateFeatures="yes" Minimum="0.0.0.0" Property="WIX_UPGRADE_DETECTED_1"/>
</Upgrade>
<Upgrade Id="GUID_2">
<UpgradeVersion MigrateFeatures="yes" Minimum="0.0.0.0" Property="WIX_UPGRADE_DETECTED_2"/>
</Upgrade>
If you have remove the MajorUpgrade element then you must also add:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallValidate"/>
</InstallExecuteSequence>
This can only add once and will be automatically added form MajorUpgrade. The default property name in the update table is WIX_UPGRADE_DETECTED. We need to use an individual name for every instance. I have suffix it with "_". But also every other is possible.
If we look into the update table with Orca we can see all our Update codes now. But there is a new problem. If we install the second instance then MSIEXEC find an installation of one of this UpgradeCodes in the action FindRelatedProducts and uninstall it in the RemoveExistingProducts. We can install only one instance. All previous instances are removed.
Between the actions FindRelatedProducts and RemoveExistingProducts we need to clear the WIX_UPGRADE_DETECTED_xx properties of the other instances. Only the UpdateCode of the current instance must exists. I have do this with a small vbscript action:
<CustomAction Id="SetInstanceID" Script="vbscript">
InstancesCount = Session.Property( "InstancesCount" )
For i = 0 To InstancesCount - 1
If CStr(i) <> instanceNumber Then
Session.Property( "WIX_UPGRADE_DETECTED_" & i ) = ""
End If
Next
</CustomAction>
Now only the the current instance is removed in RemoveExistingProducts if already exists.

Actually, the MajorUpgrade element does work with multiple instances. The generated instance transforms replace all rows of the upgrade table with new rows that are identical except for the UpgradeCode, which is replaced by that instance's own UpgradeCode. If you extract the instance transforms from your MSI (use the MsiDb.exe tool from the SDK to extract the substorages, which are named the same as the Instance/#Id values, in order to see them in action by applying them to the MSI in Orca).

Related

WIX Updater doesn't using setup params from previous version

I have the wix project installer.
I want to use the update new version of my product.
It works fine, but still shows me all dialogs and I need to enter params.(such as install path, user credential and other).
How can I skip all dialogs and using all of these params from older (prev) installer version.
<Product Id="*" Name="$(var.ProductName) $(var.ProductVersion)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." AllowSameVersionUpgrades="yes" />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="COMPANY.Product.Installers.Server" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="ServerInstallerFiles" />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" ></Property>
<UIRef Id="WixUI_MinimalCustom"/>
<InstallExecuteSequence>
<Custom Action="DoAfterInstallJobParams" Before="DoAfterInstallJob">Not Installed or REINSTALL</Custom>
<Custom Action="DoAfterInstallJob" After="InstallFiles">Not Installed or REINSTALL</Custom>
<Custom Action="DoBeforeUnstallJob" After="InstallInitialize">REMOVE="ALL"</Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="COMPANY" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<Property Id="DoBeforeUninstallJob" Value="[INSTALLFOLDER]" />
<Binary Id="CustomActionBinary" SourceFile="$(var.SolutionDir)Output\Installers\Actions\COMPANY.Product.Installers.Server.Actions.CA.dll" />
<CustomAction Id="DoAfterInstallJob" BinaryKey="CustomActionBinary" DllEntry="AfterInstall" Execute="deferred" Return="check" Impersonate="no" />
<CustomAction Id="DoAfterInstallJobParams" Property="DoAfterInstallJob" Value="HOSTING_URL=[HOSTING_URL];DB_CONNECTION=[DB_CONNECTION];INSTALLPATH=[INSTALLFOLDER];LOGIN=[LOGIN];PASSWORD=[PASSWORD]" />
<CustomAction Id="DoBeforeUnstallJob" BinaryKey="CustomActionBinary" DllEntry="BeforeUninstall" Execute="deferred" Return="check" Impersonate="no" />
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<ComponentRef Id="cmpServerHost"/>
</ComponentGroup>
</Fragment>
<Fragment>
<DirectoryRef Id="INSTALLFOLDER">
<Directory Id="ServerHost" Name="ServerHost">
<Component Win64="yes" Id="cmpServerHost" Guid="a4a81104-1e30-463d-87e1-e8a79b4c6829">
<File Id="ServerLog4netConfig" Source="$(var.SolutionDir)..\Logging\log4net.config" />
<RegistryValue Root="HKLM" Key="Software\[Manufacturer]\$(var.ProductName)" Type="string" Value="[INSTALLFOLDER]" KeyPath="yes" Name="COMPANYInstallPath"/>
<File Id="AppVersion" Source="$(var.SolutionDir)Output\Installers\Actions\COMPANY.Product.Installers.Server.Actions.CA.dll" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
Windows Installer does not persist properties. You have to do it yourself. Here is an example.
http://robmensching.com/blog/posts/2010/5/2/the-wix-toolsets-remember-property-pattern/
Remember Properties: Persisting properties allows you to read back the settings from the first version.
Dialog Control & Order: In order to skip dialogs you need to detect whether a major upgrade is taking place, if you use major
upgrades (which you do based on that source file), and then control
the dialog flow accordingly using conditioning and property values. This requires quite a bit of work and
testing. I would avoid it if you can.
Easy Mode: Just disabling (write protect) or hiding the dialogs fields that contain settings written in the first setup might be
preferable (rather than changing the dialog sequence). You can use conditions and conditioning for both purposes.
Maintenance GUI: For minor upgrades, repair and uninstall the dialog set will be different from the original installation. You will get a "maintenance dialog set" presented rather than the "installation dialog set".
Major Upgrade: A pecularity occurs when you install upgrades via Windows Installer's major upgrade mechanism. Because of how this works technically you get the installation dialog set for the new version as well. This is because it is technically a fresh install of that new product code. The fact that the older version gets uninstalled as part of the process is besides the point. You are not installing a new minor version, you are uninstalling and reinstalling effectively.
WIX_UPGRADE_DETECTED: There is a property that is set in a standard WiX package. It is WIX_UPGRADE_DETECTED. It can be used to detect when a major upgrade is taking place and hence used in conditions to adjust the dialog order of a major upgrade installation. Here are more details on this property, along with description of UPGRADINGPRODUCTCODE - which is another property that is set in the setup being uninstalled (not in the new one being installed).
Here is a quick list of different ways to change WiX GUI.
Wix, custom dialog when previous version exists (customize dialogs when previous version exists).
Ran out of time. Persisting this, will update later.
Some Links:
Removing Default dialogs from MSI

Doing Major Upgrade in Wix creates 2 entries in Add/Remove Programs

I've followed the official Major Upgrade guide and I seem to be missing something.
Here is my MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades="no"
AllowSameVersionUpgrades="no"
Disallow="no"
IgnoreRemoveFailure="no"
MigrateFeatures="yes"
Schedule="afterInstallInitialize"
DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="tenlira.ini" Guid="*">
<File Id="tenlira.ini" Source="..\ConfigurationFile\x64\tenlira.ini" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<ComponentRef Id="tenlira.ini" />
</Feature>
</Product>
</Wix>
All it does is simply installing a single file as an example. So far, so good. Now, all I do is add another Component and File and off course the corresponding ComponentRef in Feature. I specifically leave the Version as is: 31.00.0000. What I expected is that the new installer will not perform a Major Upgrade, but it does. Why? Also, there is now 2 entries in Add/Remove Programs.
Please help me find out what am I missing here. Thanks. Refael.
UPDATE:
Posting the question got me to reread the documentation again and I discovered that the AllowSameVersionUpgrades thingy in the MajorUpgrade element should be set to yes. This time there is only one entree in the Add/Remove Programs, but it still performs Major Upgrade. Why?
UPDATE: Here is a list to help debug failing major upgrades by identifying the most common problems: Common causes of failed major upgrades
Major Upgrade - "The Old, Manual Way"
I guess you are hitting an oddity that may not be handled entirely as expected by the WiX MajorUpgrade element by combining the auto-generated product GUID, the AllowSameVersionUpgrades set to yes and keeping the version number the same.
I can't see any obvious way to set the MinInclusive attribute in WiX's MajorUpgrade element - I could be mistaken, there might be a way I am unaware of. For what it is worth, I am not too keen on allowing "same version upgrades".
However, you could try to "use the old way" to author the Upgrade table using the "older elements" Upgrade and UpgradeVersion. The MajorUpgrade element is essentially a "convenience" feature to set up your major upgrades easily, and I believe it works for most users. Bob Arnson has a blog explaining the introduction of the MajorUpgrade element. This blog also shows a sample of how to do things "manually" with the "older elements" Upgrade and UpgradeVersion (do check it out).
I made a quick mock-up that might do what you want, it is just a "rough draft" - can't make any guarantees. I use preprocessor defines to set some variables that can be referenced in the WiX source file - as a C++ developer this is a piece of cake for you so I won't waste time explaining it - the source should make sense:
<?define MyProductVersion = "31.00.0000" ?>
<?define MyProductCode = "PUT-GUID-HERE" ?>
<?define MyUpgradeCode = "PUT-GUID-HERE" ?>
<!--Recommendation: set a path variable that you can redirect at will to a new release folder (new build output folder): -->
<!-- <?define MyBasePath = "C:\Projects\MyApp\Release\31.00.0000\" ?> -->
<!-- SAMPLE:
<Component Win64="yes" Feature="MainApplication">
<File Source="$(var.MyBasePath)\myapp.exe" />
</Component> -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="$(var.MyProductCode)" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="$(var.MyUpgradeCode)" Version="$(var.MyProductVersion)">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<!-- Major upgrade -->
<Upgrade Id="$(var.MyUpgradeCode)">
<!-- Downgrade Protection -->
<UpgradeVersion Minimum="$(var.MyProductVersion)" OnlyDetect="yes" IncludeMinimum="yes" Property="DOWNGRADE_DETECTED" />
<!-- Major Upgrade Configuration -->
<UpgradeVersion IncludeMinimum="no" Maximum="$(var.MyProductVersion)" IncludeMaximum="no" MigrateFeatures="yes" Property="UPGRADE_DETECTED" />
</Upgrade>
<!-- Major Upgrade: Schedule RemoveExistingProducts -->
<InstallExecuteSequence>
<!-- Potential scheduling (after): InstallValidate, InstallInitialize, InstallExecute, InstallExecuteAgain, InstallFinalize -->
<RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>
<!--Launch Condition: Abort setup if higher version found-->
<Condition Message="!(loc.NewerVersionDetected)">
NOT DOWNGRADE_DETECTED
</Condition>
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<!--<ComponentRef Id="tenlira.ini" />-->
</Feature>
</Product>
</Wix>
Now the !(loc.NewerVersionDetected) has to be explained. This is a localized string (for delivering your setup in different languages). To use it, right click your WiX project in Visual Studio and go: Add New Item... => Localization File => Add. As the localization file is added, your output MSI will also now go into a en-us folder under your main output location (Debug or Release).
In the localization file, add:
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="NewerVersionDetected">A later version of [ProductName] is already installed.</String>
</WixLocalization>
And you should now be able to add new strings to this file and easily translate your whole setup using such language files.
Also add the WiX GUI extension. Right click "References". Add Reference... => Browse to WixUIExtension.dll => Double click this file, and press OK. Normal folder to find the file is: C:\Program Files (x86)\WiX Toolset v3.11\bin.
INI-Files
I just want to mention that INI files should ideally be installed via the IniFile table (entries are treated as atomic key-value pairs allowing advanced merging of keys and values for existing INI files), and not via the File table (the file is treated as a regular file either overwriting the whole existing file or leaving it in place - not enforcing any new values). The WiX element corresponding to the MSI IniFile table is naturally the IniFile element.
An ad-hoc sample:
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
Links:
Adding entries to MSI UpgradeTable to remove related products
It does a major upgrade because both MSIs have the same UpgradeCode and you have now specified AllowSameVersionUpgrades, so it does the upgrade where it didn't before.
Your build generates a new ProductCode every time, so each MSI is a new product, so you will get it installed twice if it doesn't do an upgrade and once if it does. You may have some assumption about the way upgrades work that you haven't spelled out.
I had the same problem where Version is same, but the Id is different creating multiple entries in Add/Remove programs.
My simple fix was to set AllowSameVersionUpgrades="yes".
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of $(var.ServiceName) is already installed." />

Wix upgrade msi removing already installed features

I am using the Wix Toolset to generate an .msi for my application. Everything works when I upgrade to a new version, except every time I run a newer version installation the setup doesn't detect already installed features and instead defaults to the features that are 'required' which means if the user installed any of the other features they are removed unless the user explicitly checks them for installation again.
Is there anyway to have the .msi detect which features are currently installed each time a newer version is installed?
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" UpgradeCode="9e578e3d-0119-425c-8633-f54ffaaa4929" Name="#product.name#" Version="#product.version#" Manufacturer="#product.company#" Language="1033">
<Package InstallerVersion="400" Compressed="yes" InstallScope="perMachine" Comments="#product.version#" Description="#product.description#"/>
<Media Id="1" Cabinet="myapp.cab" EmbedCab="yes" />
<!-- Installer Properties -->
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<PropertyRef Id="WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED"/>
<!-- Check Existing Install -->
<Upgrade Id="9e578e3d-0119-425c-8633-f54ffaaa4929">
<UpgradeVersion Minimum="#product.version#" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
<UpgradeVersion Minimum="0.0.0" Maximum="#product.version#" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED"/>
</Upgrade>
<Condition Message="A newer version of this software is already installed.">NOT NEWERVERSIONDETECTED</Condition>
<!-- Prerequisites -->
<Condition Message="This application requires .NET Framework 4.6 or newer. Please install the .NET Framework then run this installer again.">
<![CDATA[Installed OR WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED]]>
</Condition>
<Condition Message="This application is only supported on Windows 7, Windows Server 2008 R2 or higher.">
<![CDATA[Installed OR (VersionNT >= 601)]]>
</Condition>
...
<Feature Id="Feature_Application"
Title="Application"
ConfigurableDirectory="APPLICATIONDIR"
Level="1"
AllowAdvertise="no">
#product.applicationcomponents#
<ComponentRef Id="ApplicationShortcut" />
<ComponentRef Id="CleanupApplicationData" />
</Feature>
<!-- Feature: My Service -->
<Feature Id="Feature_Service"
Title="My Service"
Description="My Service"
ConfigurableDirectory="REPORTDIR"
Level="3"
AllowAdvertise="no">
#product.servicecomponents#
<ComponentRef Id="ServiceShortcut" />
<Component Id="MyServiceInstaller_ServiceControl" Guid="B72CAA3F-F2DB-48D2-90DD-061209AB2CE5" Directory="REPORTDIR">
<CreateFolder />
<File Id="MyService.exe" Name="MyService.exe" KeyPath="yes" Source="#product.sourcedir#\MyService\MyService.exe"/>
<ServiceInstall Id="MyServiceInstaller_ServiceInstall"
Type="ownProcess"
Vital="yes"
Name="Windows Service"
DisplayName="Windows Service"
Description="Windows service"
Start="auto"
Account="NT AUTHORITY\LocalService"
ErrorControl="ignore"
Interactive="no" />
<ServiceControl Id="MyServiceInstaller_ServiceInstall"
Name="My Service"
Stop="both"
Remove="uninstall"
Wait="yes" />
</Component>
</Feature>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallValidate"/>
</InstallExecuteSequence>
<UIRef Id="WixUI_FeatureTree" />
<UI>
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<!-- Add the GUI logic for installation -->
</UI>
</Product>
#dpb's answer would solve the problem, because the MajorUpgrade tag has a MigrateFeatures attribute with an implicit default value of yes.
However, it is only relevant if you actually want to create a major update to your product, which has implications. - This is not an option for me.
If you do not want to perform a major update, you must add the MigrateFeatures attribute to the UpgradeVersion tag and explicitly set it's value to yes.
The MigrateFeatureStates action below the InstallExecuteSequence tag is of minor importance only.
This action will not be executed if there is no MigrateFeatures="yes" attribute (implicit or explicit), as described above.
If there is a MigrateFeatures="yes" attribute, the MigrateFeatureStates action will automatically be added to the InstallExecuteSequence table of the installer.
You only need to explicitly define the MigrateFeatureStates action in the InstallExecuteSequence tag, if you want to adjust the action's position in the execution sequence.
Try using MajorUpgrade tag.
`<MajorUpgrade DowngradeErrorMessage="Can’t downgrade." />`
https://stackoverflow.com/a/11028847/7165196

Changing the TARGETDIR in WiX

I am having problems setting the TARGETDIR path. I used dark.exe to reverse engineer a working MSI file and read any posts I could find on this subject, but I seem to be unable to set the TARGETDIR to point to the path ProgramFiles\Manufacturer\Product. Below is a distilation of my WXS file which results in my application being installed to the root of my D-drive for some reason:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="FBL - Some App"
Language="1033"
Version="1.0.0.0"
Manufacturer="Foo & Bar Limited"
UpgradeCode="780286c6-e064-4402-80d8-dd2c68b56c04">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Comments="Performs some operation that is important" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="App.1.0.0.cab" EmbedCab="yes" />
<CustomAction Id="setTARGETDIR"
Property="TARGETDIR"
Value="[ProgramFilesFolder][Manufacturer]\[ProductName]"
Execute="firstSequence"
Return="check" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="C__App.exe"
Guid="{074586E9-A675-2734-A4CD-1CE520922A41}">
<File Id="F__App.exe"
Name="App.exe"
KeyPath="yes"
Assembly=".net"
AssemblyManifest="F__App.exe"
AssemblyApplication="F__App.exe"
DiskId="1"
Source="D:\SomePath\bin\Debug\App.exe" />
</Component>
</Directory>
<Feature Id="DefaultFeature" ConfigurableDirectory="TARGETDIR" Level="1">
<ComponentRef Id="C__App.exe" Primary="yes" />
</Feature>
<Icon Id="favicon.ico" SourceFile="d:\SomePath\favicon.ico" />
<Property Id="ARPPRODUCTICON" Value="favicon.ico" />
<UI />
<InstallExecuteSequence>
<Custom Action="setTARGETDIR" Before="CostFinalize" />
</InstallExecuteSequence>
</Product>
</Wix>
I'm sure I am missing something simple, but I cannot find any further information on what to do from here.
The following modifications were needed:
<CustomAction Id="SetTARGETDIR"
Directory="TARGETDIR"
Value="[ProgramFilesFolder][Manufacturer]\[ProductName]"
Return="check" />
and
<InstallExecuteSequence>
<Custom Action="SetTARGETDIR" After="InstallValidate" />
</InstallExecuteSequence>
Explanation: Use the Directory attribute instead of a property (it's a type 35 custom action) and schedule this action after InstallValidate in the execute sequence - that's when directories are checked for write access and truly set.
(Thanks to Narina Chandra Sekhar, from the WiX user group for the answer on this.)
This is strange...I had the same issue but your answer didn't work for me. All I needed was this:
<Product>
<SetProperty Id='TARGETDIR' Value='[ProgramFilesFolder][Manufacturer]\[ProductName]\' Before='FindRelatedProducts' />
...
</Product>
But then again I think something else in my installer may have been setting the TARGETDIR directory from the property; I was working with some legacy stuff.
Edit: Actually, that was a bad idea. A lot of times, some of these custom actions that are built in can be called at different parts of the installation process, so its just better to add a custom action to set the property.
Here is what worked for me:
<Product>
<CustomAction Id='SetTARGETDIR' Property='TARGETDIR' Value='[ProgramFilesFolder][Manufacturer]\[ProductName]\'/>
...
</Product>
<InstallUISequence>
<Custom Action='SetTARGETDIR' Sequence='1'/>
...
</InstallUISequence>
<AdminUISequence>
<Custom Action='SetTARGETDIR' Sequence='1'/>
...
</AdminUISequence>
Nothing worked for me so what I did is to run the msi with a command line setting the property of the installation directory. By default my program would be installed to drive C but sometimes I wanted it to be installed to D drive so here is what I did:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="XServer">
</Directory>
</Directory>
</Directory>
Here is the command line:
XServer.msi /L*v log.log APPLICATIONROOTDIRECTORY="D:\Program Files (x86)\XServer"
This actually worked for me. The CostFinalize action is where TARGETDIR Directory is defined.
<SetProperty Id="TARGETDIR" Value="[ROOTDRIVE]MyCompany" Sequence="first" Before="CostFinalize">NOT Installed AND NOT TARGETDIR</SetProperty>
I tried changing the installation dir via custom action (cause I needed code to figure out the path with code - long story), and what solved it for me what the timing - I had to schedule the custom action to:
After="CostInitialize"

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.