Why is it possible to install two MSIs with the same upgrade code? - windows

Building MSIs with WixSharp since years, I always followed this rule which basically says:
For each new release of your application, change the ProductCode but never change the UpgradeCode.
This always worked perfectly but recently I discovered that installing a newer release of my application does not replace the previous version but instead is getting installed in parallel.
Running this PowerShell script gives me this result on a test machine:
My question
What is the reason that a MSI file does not replace an existing one upon installation with the same UpgradeCode?
(I've also posted this as a question on the WixSharp GitHub repository)
Update/solution
I've finally managed to solve it. Basically I did the following things:
Removed the version string from my setups name (since MSI seems to also compare then names to check whether an upgrade is possible; only the same name seems to fit)
Changed my version number from 4 to 3 digits, as Christopher pointed out. I.e. I'm now incrementing e.g. "1.0.0" to "1.0.1" etc.
Added this code to my WixSharp ManagedProject instance:
InstallScope = InstallScope.perMachine,
MajorUpgradeStrategy = new MajorUpgradeStrategy
{
UpgradeVersions = VersionRange.OlderThanThis,
PreventDowngradingVersions = VersionRange.NewerThanThis,
NewerProductInstalledErrorMessage = "Newer version already installed.",
RemoveExistingProductAfter = Step.InstallInitialize
},
After these changes, an upgrade succeeded.

The constraint is ProductCode not UpgradeCode. Only 1 MSI per ProductCode can be installed. Attempting to do so again will be a maintenance operation, small update or minor update.
Many MSI can share an UpgradeCode. (Not a good practice though!) For example it's not required for you to author a Major Upgrade at all.
The usual cause here though is you must change the version number in the first three fields and each install must be in the same context (per-user and per-user or per-machine and per-machine). BTW that's another way to install the same ProductCode twice. One per-user and one per-machine. Again not a good practice.
Good:
1.0.0 → 1.0.1 FindRelated Products in the 1.0.1 MSI will see the 1.0.0 and tell RemoveExistingProducts to remove it.
1.0.0 → 1.0.0 or
1.0.0.0 → 1.0.0.1 Bad. FindRelated will see it as the same version and not remove it.

Related

Patching an installation using a bundle oder msi?

I have no experience in patching/upgrading an installation.
We have a wix bundle setup with a standard (wix-created) msi inside which is added to the bundle this way:
<MsiPackage SourceFile="MySetup.msi" Id="MySetupId" Cache="yes" DisplayInternalUI="no" SuppressSignatureVerification ="yes" Visible="no" >
so in Add/Remove software section there is the bundle shown, not the msi itself.
Both, the msi and the bundle, are signed.
Currently our released version is "2.1.0.BuildNumber".
The bundle.wxs has upgrade code A
The msi has product code B and upgrade code C.
Unfortunately this version contains a mean bug but we don't want to release "v2.2.0.BuildNumber" just because of this bug, but "2.1.1.BuildNumber", so we need a patch.
What is be best practise here? Should we just create a msp file described like here
http://wixtoolset.org/documentation/manual/v3/patching/wix_patching.html?
Will this break the relationship between the bundle and the msi? Will this patch be shown in Add/Remove programms section?
Or is there a possibility to use the bundle for a patch?
Goal is, that our customers just can install the patch without deinstalling the old version, but can deinstall the whole scope using the formerly released bundle.
My personal advice is do not create patches unless absolutely necessary. You avoid a lot of trouble. The main problem IMO is that patches do not fit well onto source control and CI. First, you are not able to automatically increase the build number and include it into version number - it must remain the same. Second, creating an msp patch requires the binaries from the previous build be present during the new build. In MS technology the previous msi should be present, in WiX technology you cited you will need *.wixpdb from the previous build. Third (or the first?), the patch is a one-time action which should not be automated for continuous execution by CI.
If the bundle does not include its packages into exe but download them, a new bundle version can download only changed packages so that installation time will be small. Otherwise you are out of luck.
You need to create an msp upgrade for your buggy msi. The upgrade may or may not change the msi version, but if it does then the version of msi will not match the version of the bundle. User does not see msi version anyway.
You can install msp directly. When the bundle is uninstalled, msp will be uninstalled too. I do not know whether the msp will be visible in ARP (msi is not visible).
You may create a patch bundle. This is an independent bundle with its own upgrade code. It will contain
<Bundle .... ParentName="Name of your main bundle"...>
<RelatedBundle Id="YourMainBundleUpgradeCode" Action="Patch" />
Include MspPackage with your msp into the Chain.
This bundle will be visible in Installed Updates as a child of "Name of your main bundle" and it will be uninstalled with the main bundle or when a new version of the main bundle is installed.
You will also need to include a Condition to prevent installation of patch bundle when the main bundle of this particular version is not installed. There is no documented API to detect bundles (although you may use a RegistrySearch), but you may do ProductSearch for particular version of your msi included in main bundle.
Note that a new release of the main bundle with the same version number will install in parallel (there will be two identical entries in ARP) and new release with greater version number will automatically uninstall previous release. Thus, you cannot make new release of the main bundle.

VS 2015 Installer project - Dependencies with older version Number than installed

I have an app that uses a VS 2015 installer project.
Our BONEHEAD vendor, ComponentOne, released a new version of several assemblies upon which my product depends.
Here's the rub:
Old DLL version: 4.1.20102...
New DLL Version: 4.0.20162...
The newer DLL at least have newer file dates than the older one.
Of course, the newer DLL fix real user problems brought about by the bugs in the C1 components since corrected.
While I can get to the correct DLL by having the end user fully uninstall the older version of my product and installing the newer version, this is unworkable because:
We have an auto-update function that phones home and checks for the latest patch and installs it to update prevoius version; and
Our customers are female, 60+ and cyberphobic.
The project already has the RemovePreviousVersions property set to true, and I was hoping that this did a complete uninstall silently. It does not; the six assemblies with the version error are not replaced. The DetectNewerInstalledVersion property is also set to true; I tried to install with False, and it has no effect.
I also tried to explicitly include all detected dependencies of the C1 assemblies and it has no effect.
Is there a way to force the install project to overwrite the assemblies as long as the file date is newer regardless of the wrongly-encoded version?
Edited to add the following:
I tried making a custom action to delete the offending assemblies before installing anything - it runs after the files are installed. :(
I tried InstallShield LE, only to find out that it could not discover the dependencies more than one level deep, and provided no convenient way to explicitly specify the dependencies. I also could find nothing that would let me say to overwrite the assemblies based on date or unconditionally.
Thanks for any help you can offer!
I found an effective workaround.
I already had RemovePreviousVersions set to true, so I changed the application's default folder by adding [ProductVersion] onto the end of the path.
What this accomplished was:
It deleted the old assemblies; and
It created the new assemblies in the new folder.
This solved the problem nicely. No setting REINSTALLMODE to amus; no brute force solutions.

How to stop installation if older version of software installed in windows?

I am facing a problem while packaging my latest software version in windows 7.My latest version of software is not compatible for upgrade.So if a user already have old version of software , i have to stop the installation (disable next button in the installation windows)or give some notification to Customer to remove the older version.
Is it possible this in install shield(2015)?
You will probably want to follow the same mechanism as ISPreventDowngrade uses. In the Upgrades view, there is a major upgrade item configured as Detect Only. Then in the Custom Action and Sequences view, there is an error action that only fires if the action property of that upgrade item is set.
If you duplicate both of those items with a new action property (and thus new condition), and change the upgrade item to find your earlier version range instead of future versions, you should be able to get the behavior you want.
If you expect there's a specific threshold of versions (i.e. upgrading from anything 1.0-4.0 to anything 5.0 or later requires this, but upgrading from 5.0 to 6.0 will not), you can configure the version range explicitly. If instead you expect you will always need this in the future, you can search for any previous version and let the upper range match your product. Either can be changed for any release in the future.

Installshield does not consider revision number in warning

Lets say my current production version is 1.2.3 and the new product version is 1.2.3.4.
Now, during installation, it will throw a warning message saying something like "The setup has detected the version 1.02.003 of...... already installed. This setup updates ..... to the same version that is already installed, therefore this update is not needed. Do you want to install the update anyway? "
This will be very misleading. Does anybody know a solution for this?
It is not InstallShield, but rather Windows Installer, the underlying technology has the behavior you observe. Take a look at this article, which explains how Windows Installer treats versioning.
The important part for your case is this:
Note that Windows Installer uses only the first three fields of the
product version. If you include a fourth field in your product
version, the installer ignores the fourth field.
This explains why it considers the new one to be the same version. So, the suggestion is either change the third digit, or go with small updates instead. Here is how you can apply small updates by re-installing the product.

Detemining newer version of executable in Wix

We have a software that has couple of executables inside. One of the executables is Windows service, and it doesn't change that often, usually we release many updates to the main executable, but the service version is same inside installer.
When service is installed first time or upgraded with newer version, we need to run custom action. We managed to solve first install part, but we don't know how to determine that version we're installing now is newer than one that already exists. Sort of if(newver > oldver) run custom action.
Thank you in advance
- Jack
You can try using the upgrade rules of your package. More details here: How to implement WiX installer upgrade?
Rob Mensching (the second answer in the linked thread) shows an example for upgrade rules. You should first familiarize yourself with the Upgrade table and how upgrade rules work. There isn't an easy answer or a quick fix for this in WiX.
Basically, you should have 2 upgrade rules
the first sets a property when an older version is found
the second sets another property when a newer version is found
After that you can use the older versions property to condition your custom action. For example, if the property is named OLDERVERSIONFOUND the custom action condition can be:
OLDERVERSIONFOUND
or something like
OLDERVERSIONFOUND > "1.0.0"
Your best bet is to store the "service" version somewhere in the registry, search for that registry value during upgrade and run your CA if newver > oldver (and the CA should also update said registry value to newver)
Note that Custom Actions are (generally) an admission of failure. I always try to separate out the configuration portion of setup to a pre-install (for sysadmins doing deployment) or post-install (for interactive installations) step - often a separate executable.
Declarative installations with no custom actions are much more reliable - if you can figure out how to rewrite the service so that your custom action is no longer required, you'll be much better off in the long term (this doesn't help when you're under pressure to release now, but it's something to think of for future releases)

Resources