tags:

views:

11885

answers:

8

At work we use WiX for building installation packages. We want that installation of product X would result in uninstall of the previous version of that product on that machine.

I've read on several places on the Internet about a major upgrade but couldn't get it to work. Can anyone please specify the exact steps that I need to take to add uninstall previous version feature to WiX?

+25  A: 

Finally I found a solution - I'm posting it here for other people who might have the same problem (all 5 of you):

  • Change the product ID to *
  • Under product add The following:

    <Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
    <Upgrade Id="01918121-E286-4A36-AB78-6D7EBCE2C638">  
       <UpgradeVersion
          Minimum="1.0.0.0" Maximum="99.0.0.0"
          Property="PREVIOUSVERSIONSINSTALLED"
          IncludeMinimum="yes" IncludeMaximum="no" />
    </Upgrade> 
    
  • Under InstallExecuteSequence add:

    <RemoveExistingProducts Before="InstallInitialize" /> 
    

From now on whenever I install the product it removed previous installed versions.

Note: replace upgrade Id with your own GUID

Dror Helper
Seems this question is much more popular then I thought
Dror Helper
yes, learning WiX is like trying to figure out the obscure incantations that someone decided 'made sense' to perform a simple action. Kind of like UNIX.
mmr
Hm, I suspect that I shouldn't use that particular GUID in the "Upgrade Id=", but will have to match it so something else. But what?
Anthony
Also you may have to tweak the UpgradeVersion Min and max - e.g. If your current version is less than 1.0
Anthony
Also, what exactly does "Change the product ID to *" do? Does it generate a new product Id each time? Are there consequences to your product not having a fixed Id any more? - it sounds like overkill.
Anthony
@Anthony - yes using * will cause it to generate a new product ID each time. I found that for the "automatic upgrade" to work I need a new product Id for each version and this is the simplest way to do so
Dror Helper
We need to know the ID so generate (manually) a new ID for each public release. Using the same ID for all internal betas. Works OK but you can't autoupgrade between betas which is OK for us
sascha
@Antony, @Dror Helper: I'm pretty sure you should not be using "*" to generate a new GUID here. The GUID inside (Upgrade Id="") should be hard-coded and fixed, and it should match the GUID in your (Product UpgradeCode="") attribute.
Tartley
By which I mean, don't use "*" in the upgrade Id, but do, of course use it in the product Id as Dror intended.
Tartley
note that this will remove _any_ version installed, even if it is newer than the one you are trying to install
Lucas
I think you should probably edit your example there to NOT have an actual GUID. I'm sure people will copy-and-paste that and use it verbatim. Maybe use "YOUR-PRODUCT'S-UPGRADECODE-GUID-HERE"?
Brown
There is bug in your example. MSI's `ProductVersion` only supports three version fields; therefore the fourth field will not be compared at all. See the note under VersionMin and VersionMax in http://msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Sridhar Ratnakumar
For wix2, Product ID should be `"????????-????-????-????-????????????"` instead of `"*"`
Sridhar Ratnakumar
+10  A: 

You might be better asking this on the WiX-users mailing list.

WiX is best used with a firm understanding of what Windows Installer is doing. You might consider getting "The Definitive Guide to Windows Installer".

The action that removes an existing product is the RemoveExistingProducts action. Because the consequences of what it does depends on where it's scheduled - namely, whether a failure causes the old product to be reinstalled, and whether unchanged files are copied again - you have to schedule it yourself.

RemoveExistingProducts processes <Upgrade> elements in the current installation, matching the @Id attribute to the UpgradeCode (specified in the <Product> element) of all the installed products on the system. The UpgradeCode defines a family of related products. Any products which have this UpgradeCode, whose versions fall into the range specified, and where the UpgradeVersion/@OnlyDetect attribute is no (or is omitted), will be removed.

The documentation for RemoveExistingProducts mentions setting the UPGRADINGPRODUCTCODE property. It means that the uninstall process for the product being removed receives that property, whose value is the Product/@Id for the product being installed.

If your original installation did not include an UpgradeCode, you will not be able to use this feature.

Mike Dimmick
No doubt Mike knows exactly what he is talking about, all due respect, but it makes me sigh with despair to contemplate cluttering my mind with a firm understanding of what the Windows Installer is doing. Before I know it, I'll be doing Java and .NET consulting jobs to Enterprise clients out in the godawful tech centre towns, out beyond the ring-road, filling my TPS reports and wondering why life seems so empty. I think my next project might install with NSIS, which for all its faults, like a preposterous assembly-like language, it didn't make me understand what Windows Installer is doing.
Tartley
@Tartley - go with InnoSetup, that'll save you the assembly-like language :) Make sure you grab IStool too, it helps a lot. Also -- agreed that for simple installs all this is way too complicated, but I think they really need this complexity for installing something like SQL Server 2008...
romkyns
+5  A: 

I used this site to help me understand the basics about WiX Upgrade:

http://www.tramontana.co.hu/wix/lesson4.php

Afterwards I created a sample Installer, (installed a test file), then created the Upgrade installer (installed 2 sample test files). This will give you a basic understanding of how the mechanism works.

And as Mike said in the book from Apress, "The Definitive Guide to Windows Installer", it will help you out to understand, but it is not written using WiX.

Another site that was pretty helpful was this one:

http://www.wixwiki.com/index.php?title=Main_Page

CheGueVerra
+13  A: 

The Upgrade element inside the Product element, combined with proper scheduling of the action will perform the uninstall you're after. Be sure to list the upgrade codes of all the products you want to remove.

<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
<Upgrade Id="00000000-0000-0000-0000-000000000000">
  <UpgradeVersion Minimum="1.0.0.0" Maximum="1.0.5.0" Property="PREVIOUSVERSIONSINSTALLED" IncludeMinimum="yes" IncludeMaximum="no" />
</Upgrade>

Note that, if you're careful with your builds, you can prevent people from accidentally installing an older version of your product over a newer one. That's what the Maximum field is for. When we build installers, we set UpgradeVersion Maximum to the version being built, but IncludeMaximum="no" to prevent this scenario.

You have choices regarding the scheduling of RemoveExistingProducts. I prefer scheduling it after InstallFinalize (rather than after InstallInitialize as others have recommended):

<InstallExecuteSequence>
  <RemoveExistingProducts After="InstallFinalize"></RemoveExistingProducts>
</InstallExecuteSequence>

This leaves the previous version of the product installed until after the new files and registry keys are copied. This lets me migrate data from the old version to the new (for example, you've switched storage of user preferences from the registry to an XML file, but you want to be polite and migrate their settings). This migration is done in a deferred custom action just before InstallFinalize.

Another benefit is efficiency: if there are unchanged files, Windows Installer doesn't bother copying them again when you schedule after InstallFinalize. If you schedule after InstallInitialize, the previous version is completely removed first, and then the new version is installed. This results in unnecessary deletion and recopying of files.

For other scheduling options, see the RemoveExistingProducts help topic in MSDN. This week, the link is: http://msdn.microsoft.com/en-us/library/aa371197.aspx

Brian Gillespie
Good point about efficiency. Thanks.
Alek Davis
+17  A: 

The following is the sort of syntax I use for major upgrades:

<Product Id="*" UpgradeCode="PUT-GUID-HERE" Version="$(var.ProductVersion)">
 <Upgrade Id="PUT-GUID-HERE">
    <UpgradeVersion OnlyDetect="yes" Minimum="$(var.ProductVersion)" Property="NEWERVERSIONDETECTED" IncludeMinimum="no" />
    <UpgradeVersion OnlyDetect="no" Maximum="$(var.ProductVersion)" Property="OLDERVERSIONBEINGUPGRADED" IncludeMaximum="no" />
</Upgrade>

<InstallExecuteSequence>
    <RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>

As @Brian Gillespie noted there are other places to schedule the RemoveExistingProducts depending on desired optimizations. Note the PUT-GUID-HERE must be identical.

Rob Mensching
+4  A: 

I would suggest having a look at Alex Shevchuk's tutorial. He explains "major upgrade" through WiX with a good hands-on example at From MSI to WiX, Part 8 - Major Upgrade.

Faraz
Thanks for the link to that article...it's fantastic!
Robert P
+2  A: 

I'm using the latest version of WiX (3.0) and couldn't get the above working. But this did work:

<Product Id="*" UpgradeCode="PUT-GUID-HERE" ... >

<Upgrade Id="PUT-GUID-HERE">
  <UpgradeVersion OnlyDetect="no" Property="PREVIOUSFOUND"
     Minimum="1.0.0.0"  IncludeMinimum="yes"
     Maximum="99.0.0.0" IncludeMaximum="no" />
</Upgrade>

Note that PUT-GUID-HERE should be the same as the GUID that you have defined in the UpgradeCode property of the Product.

Merill Fernando
+1  A: 

In the newest versions (from the 3.5.1315.0 beta), you can use the MajorUpgrade element instead of using your own.

Ant