WiX: is there a way to tell what file isn't being overwritten in a major upgrade?

60 views Asked by At

I have a big program in WiX that uses a bunch of MSIs, C# custom action programs, UIs, bootstrapper, you name it, it's there.

I'm having this problem: when I run a major upgrade, the previous version isn't being erased. That is, if I upgrade from version 1.0.0.x to 1.1.0.x, Programs & Features shows that both versions are installed on the machine.

This is a common problem, with many solutions here on SO. None of them are working for me -- if there's a post of SO about this, I've tried it.

I've been told that there's a one-to-one relationship between components in a major upgrade. That is, for every component that is removed, another component has to be added. When it's NOT a one-to-one relationship is when the old version doesn't get removed -- because there are still old components hanging.

Is there a way to determine what components are hanging? Like, in the log files or something? If I could determine what MSI is having the problem I could be far more proactive in solving the issue.


EDIT:

Although I haven't solved the problem, thanks to Mr. Urman's suggestions I may be on the right track.

I created that registry key, but... it didn't seem to do anything. However, I did search my uninstall logs for the word "Disallow", and I found this phrase 9 times:

Disallowing uninstallation of component: {GUID-HERE} since another client exists.

Also, this phrase appears before each grouping of the "Disallow" phrase:

PROPERTY CHANGE: Adding INSTALLLEVEL property.  It's value is '1'.

This gives me something to go on. However, I can't seem to find the GUIDs that are mentioned! They're not in my solution nor are they searchable in the registry. Besides searching the registry, is there a way (Windows 7 32 bit) to find out what component a specific GUID corresponds to?

1

There are 1 answers

1
Michael Urman On

I've been told that there's a one-to-one relationship between components in a major upgrade. That is, for every component that is removed, another component has to be added. When it's NOT a one-to-one relationship is when the old version doesn't get removed -- because there are still old components hanging.

This is not strictly true. It's quite true of minor upgrades, and in certain configurations (those involving a late RemoveExistingProducts) major upgrades are just as picky. But your typical major upgrade functions more like the user had chosen to uninstall the old version, then to install the new version. Start by verifying your assumptions: make sure you have a proper major upgrade (you changed your ProductVersion and Product Code, and have the right entries in your Upgrade table, right?). Then diagnose.

How best to identify what's going on? In my experience, log files are your best bet. Since the older version is being uninstalled indirectly, you cannot use command lines to log it. So instead set the Logging policy by creating or setting the following registry value. (Remove it later when you want to revert the setting.)

HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer
Value (Reg_SZ): Logging
Data: voicewarmup

Then run your major upgrade, find the appropriate log file that was generated in %temp%. (Consider cleaning out %temp% ahead of time to make finding it easier. Or sort by date.) Look especially at the uninstallation (which you can identify by ProductVersion, or the presence of UPGRADINGPRODUCTCODE). I'd look especially for lines like Disallowing uninstallation of component ... that contain a component GUID.

Once you have that GUID, you have to figure out what component it is, and how it got into its current state. You can manually examine your built .msi files (with a tool like Orca) to find the component, but few tools will tell you all the clients. My employer's product comes with a helper tool called InstallShield Msi Sleuth that can list all the installed products referencing a component code, or you can build your own from MsiEnumProducts or Installer.ComponentClients. You cannot just search the registry directly, because Windows Installer stores GUIDs in a compressed or packed form.

Then identifying the "why" could be the hard part. Or it could be as simple as an incorrect Shared DLL reference count, especially if you've only encountered this on a test machine that has seen non-released versions of your product.

As a related alternative, but only relevant to a minor upgrade or small update, you could set the EnforceUpgradeComponentRules Policy. This helps reveal problems as you hit them, rather than allowing Windows Installer to do its best to continue anyway.