WiX MajorUpgrade Schedule="afterInstallExecute" won't overwrite even non-keyPath files
Asked Answered
P

1

2

Related to: How to keep a config file when major upgrade in wix v3.8?

Referencing: http://blogs.msdn.com/b/astebner/archive/2008/10/19/9006538.aspx, http://wixtoolset.org/documentation/manual/v3/howtos/updates/major_upgrade.html, http://www.joyofsetup.com/2010/01/16/major-upgrades-now-easier-than-ever/

If I employ <MajorUpgrade DowngradeErrorMessage="A newer version is already installed." Schedule="afterInstallInitialize" /> then the installer works almost as hoped, except that the config file and everything else is removed before the new product files are installed. I totally get that afterInstallInitialize specifies this behavior.

Yet I want to retain the .config file if it has been modified (if the create date and modified date are different) so I set it to keyPath='yes' and attempt to schedule the RemoveExisingProducts to after the reference counts have been incremented with Schedule='afterInstallExecute'.

But when I use afterInstallExecute, it does not behave as I expect during upgrades (works fine as a fresh install). Instead of overwriting the new versions of files that are not marked keyPath='yes' (everything else), all the existing files are left unmodified as their old versions. The installer thinks it was successful anyway.

Each file in my wix has its own component such as:

<Component Id="Host" Guid='*' Win64='yes'>
    <File Source='$(var.root)MyLib.dll' />
</Component>

And:

<Product Id="$(var.productCode)" Language="1033" 
    Version="$(var.version)" UpgradeCode="$(var.upgradeCode)">
    <Package Id="*" InstallerVersion="405" Compressed="yes" Platform="x64"
        InstallPrivileges="elevated" InstallScope="perMachine" />

I'm using WiX 3.8 and the Burn bootstrapper, but if I run the msi without the bootstrapper there's no change. InstallerVersion="405" vs 200 makes no difference.

I don't see any conditions like "skip if already installed" kind of stuff.

What else should I be looking for? Is what I describe the expected behavior?

Thanks!

Note: My Product Version is of the form 0.0.238 and increments with every build. So this should be OK single I'm only using the first three version components.

Here are some highlights from my log file:

  • Allowing installation of component: {...} even though a modified unversioned keyfile exists and file versioning rules would disable the component
  • ... Won't Overwrite; Won't patch; Existing file is unversioned but modified (for my one .config file. CORRECT!)
  • ... Won't Overwrite; Won't patch; Existing file is of an equal version (mostly for DLLs and EXEs)
  • ... Won't Overwrite; Won't patch; Existing file is unversioned and unmodified - hash matches source file (mostly for PDBs and XML)

If I specify the -sf linker option, to perhaps force the file version numbers to match the Product's overall version number (as far as Windows Installer is concerned) then the GAC installation fails with "Unknown table 'MsiAssemblyName' in SQL query: SELECT Value FROM MsiAssemblyName". So -sf probably isn't the right trick.

I think I want to avoid updating the .NET assembly version numbers with every build as long as the interfaces don't change and they're just bug fixes. That will make replacement on the installation machine more automatic, right? I'm not even sure if the assembly version change is what's necessary, but I'm fighting it anyway. :-)

Pericynthion answered 31/3, 2014 at 19:25 Comment(1)
Check the log if you are setting a custom REINSTALLMODE value: msdn.microsoft.com/en-us/library/aa371182(v=vs.85).aspx . Try adding REINSTALLMODE=emus on the command line for the upgrade.Auscultate
F
1

I am a bit confused reading this, but provided you have followed the component creation rules you can move RemoveExistingProducts after InstallFinalize. This will remove the old version after installing new files from the new version. This only works properly if the component referencing is correct, but will preserve changed files.

Inserting RemoveExistingProducts early in the InstallExecuteSequence will remove the old version completely, and then reinstall all files - reverting them to default provided they were not set as permanent components in the previous version. I don't think I have ever used the position after InstallExecute - I think you may be mixing up the names.

Froufrou answered 31/3, 2014 at 20:12 Comment(10)
MajorUpgrade has the reference to afterInstallExecute. Those docs explain why I don't want to wait until after InstallFinalize - then it's out of the transaction. Also, as I understand it, MajorUpgrade actually reschedules it for you (using Schedule attribute) and that it would be wrong to use some other mechanism. I do not use permanent, just the keyPath which is supposed to check for modifications before overwrite. I expect the new versions to overwrite the old versions but they don't when keyPath is falsePericynthion
Guid='*' in the component element? I haven't used this Wix feature, but if this changes the GUID for every build then this will break all component referencing and cause this file replacement problem. See my answer here: #1405600Auscultate
Documentation states "For the Component element the generated GUID is based on the install directory and filename of the KeyPath for the component. This GUID will stay consistent from build-to-build provided the directory and filename of the KeyPath do not change." Referring to Guid='*' of the Component, also supported here: "the default value is '*' which indicates that the linker should generate a stable guid."Pericynthion
I do appreciate your attention to this. Thank you.Pericynthion
Get a verbose log and see what's going on. Everything looks ok at first glance, If you're using the WiX majorupgrade element the REP will be done just before InstallFinalize. Note that overwriting of files isn't specifically to do with keyfiles, it's more about incrementing each file version of binaries you want to be updated, part of the file overwrite rules that apply during the late REP.Mathildemathis
@Mathildemathis - Thanks! I've added my log details to the Question. Do I have to also update all the assembly versions with every bug fix? Maybe that's a stupid question, but updating the assembly versions seems easily forgettable as a build step and/or troublesome for install-side assembly version bindings (which wouldn't otherwise need to be told of an internal bug fix on a DLL, for example). Or is this a WiX binary version concept unrelated to the .NET assembly version. But where is that set? I don't see Version as an attribute on Components or Files.Pericynthion
You need to increment file versions to get them updated during a patch or during an upgrade with REP at the end. That's not a WiX thing, it's the version in the files when you build them. For assemblies that's not the same as the assembly version - see assemblyfileversion to increment file version without changing assemblyversion. If the upgrade is removing the old entry in programs and features then the upgrade is working, and the filecopy log entries in a log should say that files are being overwritten because the incoming files have higher versions.Mathildemathis
He should be able to make do with REINSTALLMODE=emus I think.Auscultate
guys, I have the incrementing AssemblyFileVersion solution is pending, but I have an unrelated hangup to resolve before I can verify that this one is resolved. @Glytzhkof, you might be right about emus and it's a pain in the butt to keep those numbers incrementing (even with automated assistance) but I think that's the right way from an overall product management perspective. I'll report back.Pericynthion
It was certainly the assemblyfileversion. Now that I have those incrementing the installer is updating modified key files and overwriting others.Pericynthion

© 2022 - 2024 — McMap. All rights reserved.