1

I'm creating a Windows installer for my app using WIX, so, I start in the usual way:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    <Product Id="*" Name="Project X" Manufacturer="X LLC" Language="1033"
             Version="1.0.0.1" UpgradeCode="PUT-GUID-HERE>
        <Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine"/>

        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed."/>

Because the Id is set to *, every time I build an MSI it has a different id, but the UpgradeCode remains the same. This successfully achieves replacing the old one with a new one when there's an upgrade in version (1.0.0.2 for example).

The MajorUpgrade entry prevents a lower version, such as 1.0.0.0, from being installed.

If I run exactly the the same MSI file, it shows me a dialog to repair, uninstall or change the installation parameters.

My problem is that if I re-build the MSI, and run the new one, it installs as if there's no other copy of Project X installed and the user ends up with two entries in the Windows Apps & Features.

Is there a way to prevent that? Is there a way to prevent it without having to modify (and commit) my .wxs file or another build file each time I build? I try to have my builds as automated as possible and having to open a file a change it each time would be really annoying.

Regarding passing the version number to candle.exe, it doesn't solve the problem. That would still require storing the version number in the repo, creating commits for each test of the installer. It's the same problem whether I have to write the number manually in the wxs file or I have to write the number manually in the pom.xml (that's the build tool's config) or whether it's generating during build and stored on a file that then I have to commit to the repo so that the number keeps monotonically increasing for myself and all developers involved.

In case this matters, I'm using Git as my source control system, and Maven as my building tool, calling heat.exe, candle.exe and light.exe. Specifically, I'm not using Visual Studio.

Regarding the similar question WIX. How to perform Major Upgrade with same version and different product code?, both the question and the answer assume it's ok to modify the .wxs file to increment the version number each time you build an installer to test. I don't think it's acceptable. I already knew this was possible because this is what MajorUpgrade does and I took note in this question.

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
  • Hi, I removed your upgrade GUID. This is one of the more dangerous GUIDs for others to copy and paste into their own WiX projects (which happens). They could end up uninstalling your product as they install their own since you would share the upgrade code. My answer below is rushed, please take it for what it is. I will check back for comments. – Stein Åsmul Apr 24 '18 at 02:03
  • Thank you. I appreciate the concern. It was a fake guid that I generated for the question, so, no security issue. – Pablo Fernandez Apr 24 '18 at 02:28

3 Answers3

0

I am in a hurry, I don't have time to read your question in the detail I would like to. However, skimming it I think I dealt with something similar a while back, and I decided to try the old-style major upgrade elements in WiX to get more control over how the Upgrade Table ends up being populated. The Major Upgrade is a convenience feature, using the old-style elements you get more fine grained control of the Upgrade Table.

I am not sure whether this is what you are after, but let me try to link to the answer I am referring to: Doing Major Upgrade in Wix creates 2 entries in Add/Remove Programs. As I recall it, I changed it so running a same-version MSI with different product codes triggers a "downgrade not allowed-message", and hence prevents a new version from installing on top of an existing version. You can then uninstall the old version from Add / Remove programs manually, or right click the old MSI and select Remove. Right clicking the new MSI and going Remove will not work - since this MSI has a new product code, and will not be able to uninstall the previous version this way.

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • Ideally, I'd like the same-version-different-id to behave as an upgrade, that is, replacing the current one. Aside from that, your solution successfully prevents having two copies to appear in the Apps & Features by preventing the second attempt from installing. It works. – Pablo Fernandez Apr 24 '18 at 11:28
  • If you have binary files with Version resources (which include Assemblies with FileVersion data) and those versions don't change, then by default your newer installation will not replace the files present in the older installation. That is why the safer option is to do what Stein mentions: block the installation if the version isn't newer. – B. Murri Apr 28 '18 at 21:19
  • @B. Murri Setting the property [REINSTALLMODE](https://msdn.microsoft.com/en-us/library/windows/desktop/aa371182%28v=vs.85%29.aspx) to `emus` can mitigate this problem (overwrite same version and older version files). This is better than the insane setting `amus` which will downgrade any file regardless of version. This force-downgrade approach was mentioned and described by Chris Painter in his answer - I believe we both agree that this `amus` setting is horrendous. One day I might write up a long list of potential side effects. It is worse than people realize at first. – Stein Åsmul Apr 29 '18 at 01:55
  • Oh, and I should add that `emus` should be somewhat safer, but can cause more reboot prompts (and some other, more technically intricate side-effects - especially on older OS versions) since files that are in use during installation could be attempted replaced, and the installer therefore schedules a reboot. This is particularly the case with services - especially if you don't schedule a proper stop service command via the ServiceControl table on install (a common design hiccup). – Stein Åsmul Apr 29 '18 at 02:06
  • And a final point: I don't recollect how `emus` treats non-versioned files. Hopefully it will preserve them and not force-overwrite them. – Stein Åsmul Apr 29 '18 at 02:33
  • Non-versioned files are overwritten with emus unless the last-modified time is different than the creation time. – B. Murri Apr 30 '18 at 07:04
-1

This is because your ProductCode GUID is being randomly generated each build but your ProductVersion isn't being incremented. You need to follow the format 0-255,0-255,0-255 (fourth allowed by ignored per spec) and increment it each build. Then each MSI will perform a major upgrade resulting in one entry.

This machine is now in a bad state so cleaning it up could be fun. I'd uninstall all the legacy instances first then move forward.

Christopher Painter
  • 54,556
  • 6
  • 63
  • 100
  • I remember getting errors when there wasn't a fourth number in the version. Aside from that, there's no solution here. I already know that when I increment the version, it behaves correctly thanks to `MajorUpgrade`, but I'm not going to increment each time I try my own app. I only increment version when I'm releasing a new version. Otherwise there would be a lot of confusing gaps in what I release and I would have a lot of useless commits in my repo. – Pablo Fernandez Apr 23 '18 at 19:57
  • Your asking for opinion not answer. I'm just telling you how MSI works and why you are getting parallel entries. You can look at incrementing your dev/ci builds ( 0.0.1, 0.0.2, 0.0.3 ) and then have a release build that you specify (1.0.0, 1.0.1 ) without regard to the previous. Another option you could look at is this: https://stackoverflow.com/questions/20710184/wix-how-to-perform-major-upgrade-with-same-version-and-different-product-code – Christopher Painter Apr 23 '18 at 20:01
  • I'm not asking for an opinion. I wrote in the question itself that I knew how `MajorUpgrade` worked, but I don't want to have to, every time I want to try the installer, open the `wsx` file, increment the version, save, commit, push, build and then test. This is quite annoying to do for me and other developers in the same team that will get a stream of meaningless commits, and also, I could run out of Build numbers, as there's only 256 entries in each of the quad version entries. – Pablo Fernandez Apr 23 '18 at 20:18
  • The answer has been given. The opinion part of the question is what should your versioning scheme be with regards to your branches and CI strategy. There are many answers to this. I'm just trying to tell you they need to be unique and incrementing to avoid the problem you are having. How you do that is up to you. FWIW, I have 2 favorite ways and I've never run out of version #s and I don't push them every time they change. They get injected by my build automation . – Christopher Painter Apr 24 '18 at 10:55
  • I just realized who you are. We really want to help you but you need to let us help. Between myself, Bob and Stein you are talking to 3 of the top 6 MSI experts in the world. Trust us and let us guide you to a clean way of handling this. – Christopher Painter Apr 24 '18 at 10:58
  • I haven't checked Stein's answer yet, but for me, the problem with the answer is that it's telling me to do something that I already discarded as a non-working solution (change the version every time I make a build). So, the actual answer might: This is impossible and you just have to manually uninstall your app every time you try a new build. – Pablo Fernandez Apr 24 '18 at 11:03
  • I can't help you without touching on best practices. I can't touch on best practices without you accusing me of giving you opinion. One thing you can try (not a best practice ) is to set MajorUpgrade@AllowSameVersionUpgrades to yes and the the REINSTALLMODE property to AMUS. This should allow different builds with the same version number to replace each other in add/remove programs. It's still not a best practice though because now you have no way of knowing which build is on a machine because your version numbers aren't unique. This is a violation of the most basic CM rules. – Christopher Painter Apr 24 '18 at 11:20
  • Chris, if you see my comment above to my answer, I have had some luck using `emus` (overwrite same and older version file) instead of `amus` (freebasing downgrade) - but I still don't like this overwrite approach. *I don't like version-identical, but binary-different executables of any sort for deployment*. Version-identical, binary-different for ad-hoc developer QA? Yes, alright. For deployment to QA teams for testing? Maybe - but only for domestic peace (imho: makes little sense to waste your QA teams time with this approach - some day you will regret it). For public deployment: no, no, no. – Stein Åsmul Apr 29 '18 at 02:15
  • Oh I don't "like" it either. Sometimes people won't listen to what they need so you reluctantly give them what they want. My official answer above is what they need. The comments are a "well if you insist" – Christopher Painter Apr 29 '18 at 11:10
-1

Generate the version number in the build system and pass it to the candle.exe command line:

candle.exe -dProductVersion=<value>

Then refer to the preprocessor variable:

<Product Version="$(var.ProductVersion)" ...

Note that only the first fields in the product version are limited to 255. The third (and fourth, if you use it) can be up to 65535.

Bob Arnson
  • 21,377
  • 2
  • 40
  • 47
  • Thank for the info about the third and fourth going up to 65535. That's actually useful. About the problem of the question itself, this would move having to modify the `.wxs` to having to modify the Maven `pom.xml` to keep track of this build number (unless I'm missing something about generating the version number). – Pablo Fernandez Apr 23 '18 at 21:04
  • That depends on how you generate it. But that's outside the scope of WiX or Windows Installer. – Bob Arnson Apr 24 '18 at 01:00
  • I don't see how it's possible at all to generate a monotonically increasing number that's bellow 65k without keeping track of the last one that was used. So, "generating a version number outside" doesn't solve the problem of Wix installing the same version of the app twice. – Pablo Fernandez Apr 24 '18 at 01:38
  • 1
    It's entirely possible using every build automation system that I've ever used. – Christopher Painter Apr 24 '18 at 11:04
  • Note that, while the third (and, technically, the fourth) part of the version is legally 0-65535, there's an ICE (I forget which one) that returns a failure if either parts value is greater than 32757. – B. Murri Apr 30 '18 at 07:10