I'm trying to grab an old file that only exists in old installations and is not replaced in our latest version, and move that old file (if it exists) into our new install directory. I understand that CopyFile
should be able to do this, but I cannot get it to work. I've tried a bunch of different arrangements for CopyFile
, but all of it has just been guesswork based on the vague documentation and snippets I've found online, and none of it has actually copied the file.
I believe at least one problem I'm seeing is that the old files are all deleted before I can get CopyFile
to run. That's the problem I find, at least, when I try to implement this CopyFile
code: https://subscription.packtpub.com/book/application-development/9781782160427/2/ch02lvl1sec20/copying-and-moving-files
Anyway, I would really appreciate sample WXS code, integrated into what I already have below so there's no confusion about how to use it. I generally don't know enough about the entire WXS/MSI ecosystem to understand how to implement abstract suggestions or generalities, so those probably won't be much use to me, unfortunately.
Here is the old file that I want to copy:
C:\Users\myuser\AppData\Roaming\MyCompanyName\MyApp 1.1.1\vistadb.vdb6
I would like it to end up here (again, if it actually exists):
C:\Users\myuser\AppData\Roaming\MyCompanyName\MyApp 2.0.0\vistadb.vdb6
Here is my current WXS file, without any of my failed attempts to add CopyFile
:
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='MyApp 2.0.0' Id='NEW-VERSION-GUID-CODE' UpgradeCode='PRODUCT-UPGRADE-GUID-CODE'
Language='1033' Codepage='1252' Version='2.0.0' Manufacturer='MyCompany, LLC'>
<Package Id='*' Keywords='Installer' Description="MyApp 2.0.0 Installer"
Comments='This is MyApp.'
Languages='1033' Compressed='yes' SummaryCodepage='1252' Manufacturer='MyCompany, LLC'
InstallerVersion='500' InstallScope="perUser" InstallPrivileges="limited" />
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of MyApp is already installed." />
<Upgrade Id='PRODUCT-UPGRADE-GUID-CODE'>
<UpgradeVersion OnlyDetect='no' Property='SELFFOUND'
Minimum='2.0.0' IncludeMinimum='yes'
Maximum='2.0.0' IncludeMaximum='yes' />
<UpgradeVersion OnlyDetect='no' Property='NEWERFOUND'
Minimum='2.0.0' IncludeMinimum='no' />
<UpgradeVersion OnlyDetect='no' Property='PREVIOUSFOUND'
Maximum='2.0.0' IncludeMaximum='no' />
</Upgrade>
<Media Id='1' Cabinet='Sample.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
<Property Id='DiskPrompt' Value="MyApp 2.0.0 Installation [1]" />
<Icon Id="myapp.exe" SourceFile="dist\myapp.exe" />
<Property Id="ARPPRODUCTICON" Value="myapp.exe" />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='AppDataFolder' Name='PFiles'>
<Directory Id='MyCompanyDir' Name='MyCompanyName'>
<Directory Id='INSTALLDIR' Name='MyApp 2.0.0'>
<Component Id='MainExecutable' Guid='MAIN-EXE-GUID-CODE'>
<File Id='MyAppEXE' Name='myapp.exe' DiskId='1' Source='dist\myapp.exe' KeyPath='yes' Checksum="yes">
<Shortcut Id="startmenuMyApp" Directory="ProgramMenuDir" Name="MyApp 2.0.0" WorkingDirectory='INSTALLDIR' Icon="myapp.exe" IconIndex="0" Advertise="yes" />
</File>
</Component>
<Component Id='UninstallComponent' Guid='ONUNINSTALL-EXE-GUID-CODE'>
<File Id='UninstallEXE' Name='uninstall.exe' DiskId='1' Source='dist\uninstall.exe' KeyPath='yes' Checksum="yes" />
</Component>
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="MyApp 2.0.0">
<Component Id="ProgramMenuComp" Guid="PROGRAMMING-MENU-GUID-CODE">
<RemoveFolder Id='ProgramMenuFolder' On='uninstall' />
<RemoveFolder Id="RemoveINSTALLDIR" Directory="INSTALLDIR" On="uninstall"/>
<RemoveFolder Id="RemoveMyApp" Directory="MyCompanyDir" On="uninstall"/>
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='UninstallComponent' />
<ComponentRef Id='ProgramMenuComp' />
</Feature>
<Property Id="WixShellExecTarget" Value="[#MyAppEXE]" />
<CustomAction Id="LaunchFile" FileKey="MyAppEXE" ExeCommand='[OriginalDatabase]' Return='asyncNoWait' Impersonate="yes" />
<CustomAction Id="InterruptingUninstall" FileKey="UninstallEXE" ExeCommand='UninstallAlert' Impersonate="yes" />
<CustomAction Id='AlreadyUpdated' Error='MyApp is already installed.' />
<CustomAction Id='NoDowngrade' Error='A newer version of MyApp is already installed.' />
<InstallExecuteSequence>
<Custom Action='LaunchFile' After='InstallFinalize'>NOT Installed</Custom>
<Custom Action="InterruptingUninstall" Before="RemoveFiles">(REMOVE~="ALL") AND (NOT UPGRADINGPRODUCTCODE)</Custom>
<Custom Action='AlreadyUpdated' After='FindRelatedProducts'>SELFFOUND</Custom>
<Custom Action='NoDowngrade' After='FindRelatedProducts'>NEWERFOUND</Custom>
</InstallExecuteSequence>
</Product>
</Wix>
Thanks in advance for any assistance you can offer!
UPDATE: Here is what I did to fix it, thanks in part to the suggestion from Vivek Jaiswal. I changed MajorUpgrade
to include a Schedule
value, which tells the installer when to remove the old version.
<MajorUpgrade
AllowSameVersionUpgrades="yes"
DowngradeErrorMessage="A newer version of MyApp is already installed."
Schedule="afterInstallFinalize"
/>
I created another CustomAction
to back up the data, launching it from the same EXE that I'm already using for another custom action.
<CustomAction Id="BackupData" FileKey="UninstallEXE" ExeCommand='BackupVDB' Impersonate="yes" />
Lastly, I changed the InstallExecuteSequence
to look like this. Note the addition of BackupData
and the change to LaunchFile
.
<InstallExecuteSequence>
<Custom Action="InterruptingUninstall" Before="RemoveFiles">(REMOVE~="ALL") AND (NOT UPGRADINGPRODUCTCODE)</Custom>
<Custom Action='AlreadyUpdated' After='FindRelatedProducts'>SELFFOUND</Custom>
<Custom Action='NoDowngrade' After='FindRelatedProducts'>NEWERFOUND</Custom>
<Custom Action='BackupData' Before='RemoveExistingProducts'>PREVIOUSFOUND</Custom>
<Custom Action='LaunchFile' After='RemoveExistingProducts'>NOT Installed</Custom>
</InstallExecuteSequence>
In addition to all of that, I added the BackupVDB
command to my UninstallEXE
app to back up the file in a temporary location, and when MyAppEXE
launches, at the LaunchFile
CustomAction
, it checks to see if the backed up file is present and deals with it as necessary.
CopyFile shouldn't work in case of upgrading from previous version. By the time CopyFile action runs, RemoveExistingProducts action had already removed the previous version of your app.
This problem requires two fixes.
Upgrading to future releases: You need to handle this in current installer so that it fixes in next version handling future upgrades. By setting below flag in required component might help in this scenario.
Component NeverOverwrite="yes"
Upgrading from previous version: In this case, uninstallation will be executed from cached msi which is already installed. So, we can't make any changes in cached one. To handle this, You need to write two custom actions in current installer.
Backup file from existing version before it's get removed. This custom action must be schedules before RemoveExistingProducts action.
Move file from backup location to current installation directory. This action must be scheduled after InstallFiles action.