WIX installing files, override - wix

Hi I am installing files into a directory using WIX with the code below.
<Directory Id="CMSICONSDIR" Name="CMSIcons">
<Component Id="CMSICONSDIR_C" Guid="B0328FBF-D9F7-4278-B16C-28650016FF86" SharedDllRefCount="no" KeyPath="no" NeverOverwrite="no" Permanent="no" Transitive="no" Location="either">
<CreateFolder/>
<File Id="AddCamera.png" Name="AddCamera.png" DiskId="1" Source="..\..\OrionVEWorld\bin\Release\CMSICons\AddCamera.png" KeyPath="no" />
<File Id="aldownloadsmall.png" Name="al-download-small.png" DiskId="1" Source="..\..\OrionVEWorld\bin\Release\CMSICons\al-download-small.png" KeyPath="no" />
They way my application works is that a user can copy their own files in that directory overriding with what they prefer.
The problem is when I do my next install for an update, its overrides those files with the files stipulated in the install.
How do I ensure that when I run my install it does not override the existing files that are there and only adds new ones.
Unfortunately in other case I do need files that override what is there.
I do have an upgrade script section which can affect this as below
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="$(var.ProductVersion)" OnlyDetect="no" Property="NEWERVERSIONDETECTED"/>
<UpgradeVersion Minimum="1.0.0.0"
IncludeMinimum="yes"
OnlyDetect="no"
Maximum="$(var.ProductVersion)"
IncludeMaximum="no"
Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
Any suggestions is appreciated.

You could try changing the upgrade order by modifing the sequence of RemoveExistingProducts action. You could place it after InstallFinalize (no 4 option in the link article).
Also this article explains how windows installer handles the whole file overwrite logic.
EDIT: Also add the "Never overwrite" attribute to the components.

Try adding NeverOverwrite attribute to your components. It should do the trick.

Related

How can I keep my config file on a MajorUpgrade?

We use the wix 3.9 to create an msi for our product. Our Target: We want to deliver a config file (.txt-file) via the msi. When an config file already exists in the installation folder, the file should not be overwritten by an upgrade. Unfortunately, on an upgrade, Wix removes the configuration file.
The Product Element:
<Product Id="*" Name="$(var.AppName) V$(var.Version) $(var.TargetBuild)" Language="1033" Version="$(var.Version)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
The $(var.UpgradeCode) is static and will never be changed.
The Upgrade Tags:
<MajorUpgrade DowngradeErrorMessage="A newer version of $(var.AppName) is already installed." AllowSameVersionUpgrades="yes" />
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="1.0.0"
IncludeMinimum="yes"
OnlyDetect="yes"
Maximum="$(var.Version)"
IncludeMaximum="yes"
Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
Here is the config file:
<Component Id="ConfigComponent" NeverOverwrite="yes" Guid="GUID-HERE">
<File Id="ConfigOutput" KeyPath="yes" Name="MyConfig.config" Source="MyConfig.config.bak"/>
</Component>
In Addition, I use RemoveFolderEx to remove generated files by the Application itself. But when I commented out this block, the problem still occurs. But I want to show the codeblock for the completeness:
<Component Id="RemoveAll" Guid="MYGUID">
<RemoveFile Id="RemoveAllFilesOnUninstall" Directory="APPLICATIONFOLDER" Name="*.*" On="uninstall" />
<RemoveFolder Id="RemoveAllFoldersOnUninstall" Directory="APPLICATIONFOLDER" On="uninstall" />
<RegistryValue Root="HKLM" Key="SOFTWARE\$(var.Manufacturer)\$(var.AppName)" Name="Path" Type="string" Value="[APPLICATIONFOLDER]" KeyPath="yes" />
<util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
</Component>
Repro: At first, we install the Software and the file 'MyConfig.config' appears in the application folder as expected. After that, we make changes inside of this config file. At next, we build a second .msi and execute it. When the update is made, all files are overwritten as expected. But we are missing the file 'MyConfig.config' in the installation folder now.
UPDATE:
The attribute Permanent="yes" does also not work as expected. The config File is still removed on an upgrade:
<Component Id="ConfigComponent" Permanent="yes" NeverOverwrite="yes" Guid="GUID-HERE">
<File Id="ConfigOutput" KeyPath="yes" Name="MyConfig.config" Source="MyConfig.config.bak"/>
</Component>
What's happening during your Major Upgrade:
The CostInitialize/CostFinalize actions determine what components in the new MSI should install. The ConfigComponent decides 'not' to install because it's marked as NeverOverwrite="yes".
The old MSI is removed during the RemoveExistingProducts action. The previous config file is removed.
The new MSI is installed. The ConfigComponent does not get installed based on the check from step 1.
A quick solution (although I'm sure there are better approaches out there):
Going forward, mark your ConfigComponent with Permanent="yes" so that MSI never removes it. You'll need to add a custom action that removes the file, and condition it on "$ConfigComponent=2 And Not UPGRADINGPRODUCTCODE" so that it only executes when the component is set to be deleted through a modify or full-uninstall, but not an upgrade.
If your MSI is already shipped to the world and you need to fix the upgrade scenario you'll need to write a custom action that copies the config file to a backup location before the old MSI removes it. Then another custom action to copy the config file back into the correct directory.

Understanding PackageCode, ProductCode and UpgradeCode of WIX with multi instances

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).

Run the Update sql Script on Existing Database using WIX Installer during Upgrade

I am creating installer for Creating the databaase using WIX. But I could not able to find a way to run the udate script during Upgrade.
Code for Create DB
<Directory Id="DFDB" Name="DealFoundryDataBase" FileSource="$(var.SolutionDir)DealFoundrySetup/DataBaseScripts">
<Component Id='SqlComponent_Files' Guid='{07DB58E6-5AFC-4BB0-84EC-C5EC6B0E5CA7}' KeyPath='yes'>
<File Id="CreateTable_sql" Name="CreateTable.sql"/>
<File Id="InsertStatements_sql" Name="InsertStatements.sql"/>
<File Id="DFCoreScript_sql" Name="DFCoreScript.sql"/>
</Component>
<Component Id='SqlComponent' Guid='{C5412828-84FB-4CC5-AC71-AC246B9D09E8}' KeyPath='yes'>
<Condition><![CDATA[NOT OLDER_VERSION_FOUND]]> </Condition>
<sql:SqlDatabase Id='SqlDatabase' Database='[PRO_DFDATABASE_NAME]' User='SQLUser' Server='[PRO_DFDATABASE_SOURCE]'
CreateOnInstall='yes' DropOnUninstall='yes' ContinueOnError='yes'>
<sql:SqlScript Id='CreateTable' BinaryKey='CreateTable' ExecuteOnInstall='yes' />
<!--<sql:SqlScript Id='InsertStatements' BinaryKey='InsertStatements' ExecuteOnInstall='yes'/>-->
</sql:SqlDatabase>
</Component>
</Directory>
<Binary Id ='CreateTable' SourceFile='$(var.SolutionDir)DealFoundrySetup/DataBaseScripts/DFCoreScript.sql'/>
<Binary Id ='InsertStatements' SourceFile='$(var.SolutionDir)DealFoundrySetup/DataBaseScripts/InsertStatements.sql'/>
<Binary Id ='MasterData' SourceFile='$(var.SolutionDir)DealFoundrySetup/DataBaseScripts/MasterData.sql'/>
<util:User Id='SQLUser' Name='[PRO_DFDATABASE_USERID]' Password='[PRO_DFDATABASE_PASSWORD]' />
The above lines of code is working fine for creting the DB on Install, but I want to run the update script during upgrade on Existing DB
Plz Help me.
Thanks in Advance.
Ahh... Versioning. So much fun.
First, make sure you have your tags set in the installer. Here is what I usually do (and this is rather complicated because you might want to check for specific versions to do different upgrade scripts):
<Upgrade Id="{YOUR GUID HERE}" > <!--never change me-->
<UpgradeVersion OnlyDetect="yes" Minimum="$(var.ProductVersion)" Property="NEWERPRODUCTFOUND" IncludeMinimum="no" />
<UpgradeVersion OnlyDetect="no" Minimum="5.0.0" Maximum="$(var.ProductVersion)" Property="OLDERVERSIONBEINGUPGRADED" IncludeMaximum="no" RemoveFeatures="All" />
<UpgradeVersion OnlyDetect="yes" Maximum="5.0.0 " Property="VERYOLDVERSIONFOUND" IncludeMaximum="no" />
</Upgrade>
You can have as many of these "versions" defined as you want, and maybe each one will run a different upgrade script for your database. They will set the properties defined in this list.
Secondly, WiX defines a well known value 'Installed' that is only used when you are doing an uninstall or upgrade:
http://msdn.microsoft.com/library/aa369297.aspx
So if you wish to only run it ONLY while doing an upgrade, you should use this:
<Condition><![CDATA[NOT Installed OR NOT VERYOLDVERSIONFOUND]]> </Condition>
If you want to run it if you are doing an upgrade or installing, it should be this way:
<Condition><![CDATA[(NOT Installed AND Installed) OR (NOT VERYOLDVERSIONFOUND AND VERYOLDVERSIONFOUND]]> </Condition>
Which is the same as not having a condition at all since it will always be true.

WiX installer - problems updating

I'm having the worst time trying to configure WiX to NOT remove some configuration files from the installation directory during updates.
I've searched and googled but I'm stuck...
Here's what I have.
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" ... >
<Product Id="PRODUCT_GUID" ...
UpgradeCode="UPGRADE_GUID">
...
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion OnlyDetect="no" Property="REMOVEOLDVERSION" Maximum="$(var.ProductVersion)" IncludeMaximum="no" />
<UpgradeVersion OnlyDetect="yes" Property="NEWERFOUND" Minimum="$(var.ProductVersion)" IncludeMinimum="no" />
</Upgrade>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallFinalize" />
</InstallExecuteSequence>
...
And the files are as followed:
<Component Id="ConfigurationFiles" Guid="ConfigurationFiles_GUID" NeverOverwrite="yes">
<File Id="SomeConf" Source=... />
</Component>
What am I doing wrong?
If the problem is really the removal of the configuration files, then I think you meant to specify Permanent="yes" instead of NeverOverwrite="yes".
However, if the configuration files are not installed by the new version of the installer (which is why they disappear after the upgrade, I presume) then they shouldn't be necessary right? I'm not sure why you would want to keep the configuration files in that case. Marking them permanent effectively makes it impossible to uninstall them.
If you are actually worried about overwriting changes made to those configuration files by the user, then I think Windows Installer will already handle this correctly. The File Versioning Rules already have a concept of "user data" based on file modification timestamps, and will not overwrite such files.

Pattern to do a wix upgrade without messing with the desktop icons of the users

The Wix setup I'm working on asks the user whether to install a shorcut from the main program on the desktop.
The problem is that during upgrades, the shortcut is removed and then recreated :
If the user moved the icon, it's likely recreated somewhere else (next free space starting from top left corner)
If the user chose to not create the icon during the initial install, upgrades with UI do not remember that the checkbox to create the icon should be "unchecked" by default, and silent upgrades just create the icon although the user explicitly chose to not have this icon created.
Is there a simple way to properly handle this situation ?
Below are informations on my wix setup :
Install is per machine
The users chooses to install the desktop shortcut via a checkbox that is added on a modified version of the "Choose destination" :
<Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="160" Width="290" Height="17" Property="INSTALLDESKTOPSHORTCUT" CheckBoxValue="[INSTALLDESKTOPSHORTCUT]" Text="!(loc.InstallDirDlgCreateDesktopShortcut)" />
In the UI tag I have the property initialized :
<Property Id="INSTALLDESKTOPSHORTCUT" Value="1"/>
This is the component to create the shortcut with the INSTALLDESKTOPSHORTCUT condition :
<Directory Id="DesktopFolder" Name="Desktop">
<Component Id="desktopconnecteurdts" Guid="a-real-guid-here">
<Condition>INSTALLDESKTOPSHORTCUT=1</Condition>
<Shortcut Id="desktopconnecteurdts" Name="DTS eXplorer" WorkingDirectory="ApplicationFolder" Icon="DTSeXplorer.exe" Target="[ApplicationFolder]\DTSeXplorer.exe" Advertise="no" />
</Component>
</Directory>
Upon launch the setup will check if an older version exists and remove the older version if found :
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion OnlyDetect="no"
Property="PREVIOUSVERSIONSINSTALLED"
Minimum="$(var.OldProductVersion)"
IncludeMinimum="yes"
Maximum="$(var.ProductVersion)"
IncludeMaximum="no"
RemoveFeatures="all" />
<UpgradeVersion OnlyDetect="yes" Property="PROJECT_DOWNGRADE"
Minimum="$(var.ProductVersion)" IncludeMinimum="no" />
</Upgrade>
The product version major does not change, for example I'm upgrading from 1.6.8.12345 to 1.7.2.56789
Thanks !
Write the value of INSTALLDESKTOPSHORTCUT to the registry during installation. Whenever your installer starts, you can read the registry and if that key exists, set it as the default value of that property.
Not sure if you can do anything about the location of the shortcut on the desktop however.
You can save and restore the setting for the shortcut using only wix.
Your property has to look like this.
<Property Id="INSTALLDESKTOPSHORTCUT" Value="1" Secure="yes">
<RegistrySearch Id="Reg64" Root="HKLM" Win64="yes" Key="Software\$(var.ProductCompany)" Name="CreateDesktopShortcut" Type="raw"></RegistrySearch>
<RegistrySearch Id="Reg32" Root="HKLM" Win64="no" Key="Software\$(var.ProductCompany)" Name="CreateDesktopShortcut" Type="raw"></RegistrySearch>
</Property>
The two 'RegistrySearch's are only there to cover both 32bit and 64bit installer, if you only use 32bit you can remove one of them.
And under your root folder add this.
<Component Permanent="yes" Id="RegistryEntries" Guid="YOUR_GUID">
<RegistryKey Root="HKLM" Key="Software\$(var.ProductCompany)" Action="create">
<RegistryValue Type="integer" Name="CreateDesktopShortcut" Value="[INSTALLDESKTOPSHORTCUT]" />
</RegistryKey>
</Component>