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

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?

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.

Related

Disable repair mode and upgrades in wix installer

We have a unique requirement to create an msi using wix,the catch is that the msi must support multiple instance installation. User should be able to use the msi to install the product more than once on a particular system, so in order to achieve this we should disable repair mode and upgrades in msi, so literally each invocation of msi should be treated as fresh install.
Is the above requirement technically feasible with Wix? I am aware that having unique product code and package code for every invocation of msi will treat the installation as fresh install. Can this be achieved using a wrapper around the msi?
You could do this with a wrapper around the MSI. In general your wrapper program would start with the base MSI, alter the ProductCode and PackageCode using the Windows Installer APIs, copy this MSI to a location on the system then install it from there.
I say "copy and install" because it's futile trying to disable repair - it's too baked into the architecture of Windows Installer. If you have each separate MSI product cached somewhere then repair will work using that unique MSI, and it also means that you could modify as well. Repair is too unpredictable to completely prevent. Any shared files can trigger repair from other installed products that share them. What do clients do if they accidentally delete files or registry entries? And there's this about keeping the source MSI available, although the list of reasons doesn't come with a lot of explanation, Rule 31:
https://blogs.msdn.microsoft.com/windows_installer_team/2006/05/24/tao-of-the-windows-installer-part-3/
There are a lot of other issue that aren't mentioned, so it's not clear if you care about patches and maintenance in general, about multiple entries in Programs/Features (that you could suppress, but how do you uninstall?) and so on. It's also not clear that each of these separate installs don't conflict with each other in any way, such as common files/registry entries, service names, files being installed in the same location with the same name.
Before sending you to the MSI SDK I should add that I dislike this instance transform concept myself, and have not used it in practice. It might be that I have become a grumpy old man! :-).
MSINEWINSTANCE: Please investigate the MSINEWINSTANCE property and read up on the MSI SDK topic: "Installing Multiple Instances of Products and Patches". And here is perhaps a better example - more practically oriented.
Also some context on why I am not too keen on this feature. Carolyn Napier was on the original MSI team - this is straight from the horse's mouth as they say.
I know some people claim success with these instance transforms (Chris Painter might be able to illuminate my claims here), but I'd rather virtualize in scenarios such as these. Please see this age-old post from serverfault.com: I want to install an MSI twice (please skim all the other answers in that "thread" too).
APP-V: I have almost zero App-V experience, but my guess is that this is what you should try to convince your manager to spend some time on investigating. Maybe call in some favors and talk to guys who are operative in current deployment. They always have the current prevailing prejudice to report - with the tricks that make things work in the real world.
Great if you can let us know how you end up solving the problem.
Disable Repair & Modify: And for the record: disabling repair and modify (buttons only) can be done by setting the ARPNOMODIFY and ARPNOREPAIR properties. But this is not what you are looking for to allow multiple instance installations. MSI is not easily fooled and knows what you have installed and when - no reason to waste time testing these "options". All these two properties do is to hide or disable the modify and repair buttons - yields nothing you need apart from that.

Getting the value at the end of a long chain of registry entries

This is my first attempt to use the registry in any depth, so bear with me...
I write small VB.net programs that interact with Excel and other programs to produce complex reports. As part of this we sometimes have to interact with a 3rd party DLL. Since this DLL is generally very rare, we took an "always install" policy, and run their installer on first-start.
Well now we have a customer who already has the 3rd party app, so the install fails (as it should). But this leaves me trying to find where the DLL/app has been installed so I can call it properly. Poking about in regedit (causing it to repeatedly crash) I have found it seems to be like this...
Installing the DLL produces an entry called APLW.WSEngine in HKEY_CLASSES_ROOT, as well as an apparently identical copy in HKEY_LOCAL_MACHINE\SOFTWARE\Classes\. Those entries both contain a CLSID which can be found in HKEY_CLASSES_ROOT\Interface\[the key]\TypeLib as well as entries for a variety of sub-parts of the install. I also find it at HKEY_CLASSES_ROOT\TypeLib\[the key], and here it has a key called \3.0\HELPDIR\ that contains the directory I'm looking for.
So...
What is the minimum number of calls I need to make to find the value in that HELPDIR key, or get Nothing or "" if any of the keys doesn't exist. In the end I either need that path, or nothing if the software has not been installed. Currently I'm making repeated calls into the reg to look up each entry and key in turn, but I suspect there is a way to chain them?
To make things slightly more complex, that \3.0\ in the path may change, the actual value is in the Version key in the original CLSID entry. If there is an easy way to add this I'll use it, but since we only work with 3.0 (AFAIK) it can be ignored.
Maybe 1. Maybe more. Don't know, this was not a very typically laid out question (which is probably why you got down voted), but I'm going to assume that you are more of a numbers / reporting person than a software engineer. So proceeding with that assumption, I will try and be helpful instead of pointing out any breaches of etiquette and provide you a couple resources that may help.
For starters, how to read a registry value:
https://msdn.microsoft.com/en-us/library/xz88758e.aspx
Secondly, the full tech spec on the Registry class in vb.net:
https://msdn.microsoft.com/en-us/library/microsoft.win32.registry(v=vs.110).aspx
Both give plenty of samples that should aid you along your way. But keep in mind that in certain situations and certain computer setups, these sorts of registry calls might require you to elevate your UAC permissions, if you run into such a case, you can try this resource, which covers in some detail how to make your applications UAC aware:
http://www.codeproject.com/Articles/17968/Making-Your-Application-UAC-Aware
I hope this helps, and good luck!

WIX force installation of a component with lower version number

I'm using AjaxControlToolkit and they decided to change their version numbering scheme. The change is documented here : http://stephenwalther.com/archive/2013/01/24/new-january-2013-release-of-the-ajax-control-toolkit.aspx
Basicaly, the newer versions have a lower file version (4.1.7.123 is newer than 4.1.60501.0, but 7 is smaller than 60501.)
Obviously, this causes issues in my MSI as it is now seeing a component with an higher version number already on the machine and thus ouputs this:
MSI (s) (7C:10) [10:04:14:996]: Disallowing installation of component: {22C7D2FC-179E-515D-B650-CE20A7B3F9E0} since the same component with higher versioned keyfile exists
How would i go and force the installation of this newer but lower-version-number component ?
P.S. Personal rant: AjaxControlToolkit guys for justifying this number by saying "And yes, I realize that 7.0123 is less than 60,919, but we ran out of numbers.". 4.2.7.123 would have worked, guys. You ran out of 3rd numbers, fine, you need to increment the 2nd.
Easiest thing to do is to install to a new location. That will avoid the checks completely. A hacked thing to do is to fake the File.Version column in the MSI but that will only get you through this once, eventually you'll need to get to a new location to address the problem.
You could also set the REINSTALLMODE to include "a" but that will just create all sorts of grief for you lately, so I can't really recommend that as an option.
Note: The AjaxControlToolkit guys did give you a huge headache. If they renamed their .dll, that would be the most helpful. Seems like the least they could do since they just broke their world so badly.

How do you correct 2 unrelated msi having the same UpgradeCode

I'm a bit light on detail but I think we have a problem.
Using the copy/paste method of boostrapping an installer project in wix, it appears we seem to have missed updating the UpgradeCode to ensure they are unique...
<Product Id="*" UpgradeCode="SOME-BAD-FOO">
So, it is my understanding that this is "not good" (r)(tm)
At the moment the users of the 2 installers with this issue are unlikely to have installed both, but they may in future.
Looking for ideas on how to fix this issue before it becomes an installed nightmare...
Maybe Windows cannot even install both at the same time?
Is there some way to perform an upgrade install/patch and change the UpgradeCode?
So, it is my understanding that this is "not good" (r)(tm)
That is really not good, you should be careful to not do that in the future as it can give you, and your users, a lot of headaches.
However, the solution is very simple. All you need to do is to change the upgrade code for one of the packages, and to add the current upgrade code in the Upgrade table for the new version, so it removes it, if it is found on the machine.
If you are sure the second version will be installed by all your users that have installed the first one, in the next release you should remove the upgrade code the from Upgrade table, to make sure you don't have any conflicts with the second package, i.e. the still using the first upgrade code.
One question I'd ask would be are you using Major or Minor Upgrades.
If Minor, I've never tried changing the UpgradeCode but not the ProductCode. I think it would be OK but I'm afraid to find out.
If Major Upgrades, do the products use different version number ranges? 1.0-1.9 , 2.0-2.9? If so, it would possible to change the UpgradeCode in both installers ( just leave the 'dirty' guid in your past ) and then use the old guid in your UpgradeTable with a version # as a the key to identifying the correct product codes.
If not, do you know every single ProductCode that was ever released to the wild for both products? A custom action could be used to query MSI for installed ProductCodes and then compare it to a list of known guids to decide whether it applies or not.
You'll have to leave the code in forever though. Old versions of software have a tendency to stick around forever.

Add missing file with msp patch

I created an installer, deployed to our test environment and got an error due to a missing dll (it was not included in the wsx file). Is it possible to create a MSP patch to ship the missing dll or is it better to simply create a whole new installer?
I tried following various examples but I keep getting this error:
DEBUG: Error 2356: Couldn't locate cabinet in stream: media1.cab.
A patch can do anything an updated MSI can do, but it is merely a packaging and delivery mechanism that delivers an update in a more compact way. Hence you must actually create a full new version of your setup to be able to then package this new update as a patch.
Important: spend no time at all testing a patch before the full upgrade is working properly. This is a complete waste of time. It creates only mysterious errors and is a very common real-world time drain.
Unless your previous setup has gone to production and hence is "out in the wild", I wouldn't waste my time with a patch. Patches require a lot of time to create and even more time to test - there is a lot of added risk and complexity, and it is only intended to be a convenient way to deliver small updates such as what you describe without having to distribute a potentially huge, new MSI file. It is not common to use patches for UAT or QA testing unless your product is really huge and takes ages to install.
Personally I feel that MSI has failed entirely when it comes to patching. It should be an easy to use, value added feature, but it has become a hugely complicated, problematic issue in its own right.
Yes, you can add a missing file through a patch. Perhaps this article will help: http://wix.sourceforge.net/manual-wix2/patch_building.htm
When creating a patch you should always modify your existing installer. You don't create a new installer from scratch. Also, never remove resources from the new version. For a patch you should either modify or add resources.
Regarding error 2356, it seems like the original installation is somehow corrupted. You can try repairing the old version before applying the patch on it.