Comment mettre en œuvre la mise à niveau du programme d'installation WiX?

233

Au travail, nous utilisons WiX pour créer des packages d'installation. Nous voulons que l'installation du produit X entraîne la désinstallation de la version précédente de ce produit sur cette machine.

J'ai lu à plusieurs endroits sur Internet une mise à niveau majeure mais je n'ai pas pu le faire fonctionner. Quelqu'un peut-il préciser les étapes exactes à suivre pour ajouter la fonctionnalité de désinstallation de la version précédente à WiX?

Dror Helper
la source

Réponses:

189

Dans les versions les plus récentes (à partir de la version bêta 3.5.1315.0), vous pouvez utiliser l' élément MajorUpgrade au lieu d'utiliser le vôtre.

Par exemple, nous utilisons ce code pour effectuer des mises à niveau automatiques. Il empêche les rétrogradations, donnant un message d'erreur localisé et empêche également la mise à niveau d'une version identique déjà existante (c'est-à-dire que seules les versions inférieures sont mises à niveau):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />
Fourmi
la source
8
Le billet de blog de Bob Arnson à ce sujet fournit de nombreuses informations intéressantes.
Dave Andersen
17
Remarque: non documenté nulle part, mais l' <MajorUpgrade>élément " " doit être placé après <Package> . Sinon, candledonne l'erreur suivante: "erreur CNDL0107: la validation du schéma a échoué avec l'erreur suivante à la ligne 1, colonne 473: l'élément 'Product' dans l'espace de noms ' schemas.microsoft.com/wix/2006/wi ' a un élément enfant non valide ' MajorUpgrade 'dans l'espace de noms' schemas.microsoft.com/wix/2006/wi '. Liste des éléments possibles attendus:' Package '. ".
Rob W
21
+1 Cette réponse doit recevoir autant de votes positifs que possible; il est très tentant d'aller avec une réponse qui a 5x les votes positifs, mais utilise des approches plus anciennes.
Lynn Crumbling
1
Bon point. J'ai ajouté un exemple pour que les gens ne l'ignorent pas simplement parce qu'il n'en a pas!
Fourmi
6
Je veux juste souligner que vous n'avez pas besoin de spécifier AllowDowngradesou AllowSameVersionUpgrades. Ils sont déjà par défaut non.
Lumineux
221

Enfin, j'ai trouvé une solution - je la poste ici pour d'autres personnes qui pourraient avoir le même problème (vous 5):

  • Remplacez l'ID produit par *
  • Sous produit, ajoutez ce qui suit:

    <Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
    <Upgrade Id="YOUR_GUID">  
       <UpgradeVersion
          Minimum="1.0.0.0" Maximum="99.0.0.0"
          Property="PREVIOUSVERSIONSINSTALLED"
          IncludeMinimum="yes" IncludeMaximum="no" />
    </Upgrade> 
  • Sous InstallExecuteSequence, ajoutez:

    <RemoveExistingProducts Before="InstallInitialize" /> 

Désormais, chaque fois que j'installe le produit, il supprime les versions installées précédentes.

Remarque: remplacez l'ID de mise à niveau par votre propre GUID

Dror Helper
la source
153
oui, apprendre WiX, c'est comme essayer de comprendre les incantations obscures que quelqu'un a décidé de «faire sens» pour effectuer une action simple. Un peu comme UNIX.
mm
6
De plus, que fait exactement "Changer l'ID du produit en *"? Génère-t-il à chaque fois un nouvel identifiant de produit? Y a-t-il des conséquences à ce que votre produit n'ait plus d'identifiant fixe? - ça sonne comme exagéré.
Anthony
10
@Antony, @Dror Helper: Je suis presque sûr que vous ne devriez pas utiliser "*" pour générer un nouveau GUID ici. Le GUID à l'intérieur (Upgrade Id = "") doit être codé en dur et fixe, et il doit correspondre au GUID dans votre attribut (Product UpgradeCode = "").
Jonathan Hartley
37
Je pense que vous devriez probablement y modifier votre exemple pour NE PAS avoir de GUID réel. Je suis sûr que les gens vont copier-coller cela et l'utiliser in extenso. Peut-être utiliser "YOUR-PRODUCT'S-UPGRADECODE-GUID-HERE"?
Brown
12
Il y a un bug dans votre exemple. MSI ProductVersionne prend en charge que trois champs de version; par conséquent, le quatrième champ ne sera pas du tout comparé. Voir la note sous VersionMin et VersionMax dans msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Sridhar Ratnakumar
89

Voici le type de syntaxe que j'utilise pour les mises à niveau majeures:

<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>

Comme @Brian Gillespie l'a noté, il existe d'autres endroits pour planifier les RemoveExistingProducts en fonction des optimisations souhaitées. Notez que PUT-GUID-HERE doit être identique.

Rob Mensching
la source
2
Je lis la section "Mise à niveau et correctif" dans le livre de Nick Ramirez sur Wix ici, et il déclare que si vous planifiez RemoveExistingProducts après InstallInitialize, alors vous DEVEZ également planifier <InstallExecute After="RemoveExistingProducts" />. Votre exemple n'a pas cela - cela signifie-t-il que le livre est faux?
Wim Coenen
3
Je ne planifie jamais explicitement InstallExecute.
Rob Mensching
1
Je ne. Dans WiX v3.6, Burn rendra les mises à niveau mineures faciles à exécuter, mais sans Burn, il nécessite une interaction manuelle de l'utilisateur (doit fournir des options de ligne de commande), ce qui rend les mises à niveau mineures essentiellement inutiles. :)
Rob Mensching
1
@RobMensching: comment éviter l'installation d'une ancienne version par rapport à une plus récente? Votre réponse fonctionne pour moi (le seul exemple de "mise à niveau majeure" que je peux obtenir du tout avec WiX v3.5.2519.0), mais il est possible d'installer une version plus ancienne (après cela, je vois les deux versions dans "Ajouter / Supprimer des programmes ").
Christian Specht
4
D'accord, je viens de trouver l' élément MajorUpgrade dans cette réponse qui fait exactement ce que je veux, y compris la prévention des rétrogradations.
Christian Specht
40

L'élément Upgrade à l'intérieur de l'élément Product, combiné à une planification appropriée de l'action, effectuera la désinstallation que vous recherchez. Assurez-vous de répertorier les codes de mise à niveau de tous les produits que vous souhaitez supprimer.

<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>

Notez que si vous faites attention à vos versions, vous pouvez empêcher les gens d'installer accidentellement une ancienne version de votre produit sur une plus récente. C'est à cela que sert le champ Maximum. Lorsque nous créons des programmes d'installation, nous définissons UpgradeVersion Maximum sur la version en cours de création, mais IncludeMaximum = "no" pour éviter ce scénario.

Vous avez le choix concernant la planification de RemoveExistingProducts. Je préfère le planifier après InstallFinalize (plutôt qu'après InstallInitialize comme d'autres l'ont recommandé):

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

Cela laisse la version précédente du produit installée jusqu'à ce que les nouveaux fichiers et clés de registre soient copiés. Cela me permet de migrer les données de l'ancienne version vers la nouvelle (par exemple, vous avez changé le stockage des préférences utilisateur du registre vers un fichier XML, mais vous voulez être poli et migrer leurs paramètres). Cette migration est effectuée dans une action personnalisée différée juste avant InstallFinalize.

Un autre avantage est l'efficacité: s'il y a des fichiers inchangés, Windows Installer ne prend pas la peine de les recopier lorsque vous planifiez après InstallFinalize. Si vous planifiez après InstallInitialize, la version précédente est complètement supprimée en premier, puis la nouvelle version est installée. Il en résulte une suppression et une recopie inutiles des fichiers.

Pour d'autres options de planification, consultez la rubrique d'aide RemoveExistingProducts dans MSDN. Cette semaine, le lien est: http://msdn.microsoft.com/en-us/library/aa371197.aspx

Brian Gillespie
la source
2
@Brian Gillespie: que signifie "... s'il y a des fichiers inchangés ..."? Quels sont les critères pour que Windows Installer décide quand remplacer un fichier, AssemblyVersion, AssemblyFileVersion, taille de fichier, ...?
donttellya
2
@donttellya +1 l'a appris à la dure. RemoveExistingProductsa été programmé pour après InstallFinalizeet les DLL n'étaient pas mises à jour car assemblyVersion était inchangé mais d'autres champs comme AssemblyProduct l'étaient. Je ne veux pas être à la merci de la routine de comparaison de fichiers - je veux juste que l'application précédente disparaisse
wal
16

Vous feriez mieux de poser cette question sur la liste de diffusion des utilisateurs WiX .

Il est préférable d'utiliser WiX avec une solide compréhension de ce que fait Windows Installer. Vous pourriez envisager d’obtenir " Le guide définitif de Windows Installer ».

L'action qui supprime un produit existant est l' action RemoveExistingProducts . Parce que les conséquences de ce qu'il fait dépendent de l'endroit où il est planifié - à savoir, si une panne entraîne la réinstallation de l'ancien produit et si les fichiers inchangés sont copiés à nouveau - vous devez le planifier vous-même.

RemoveExistingProducts processus <Upgrade> éléments de l'installation actuelle, en faisant correspondre l' @Idattribut au UpgradeCode(spécifié dans l' <Product>élément) de tous les produits installés sur le système. Le UpgradeCodedéfinit une famille de produits associés. Tous les produits qui ont ce UpgradeCode, dont les versions tombent dans la plage spécifiée et où l' UpgradeVersion/@OnlyDetectattribut est no(ou est omis), seront supprimés.

La documentation pour les RemoveExistingProductsmentions définissant la UPGRADINGPRODUCTCODEpropriété. Cela signifie que le processus de désinstallation du produit à supprimer reçoit cette propriété, dont la valeur est celle Product/@Iddu produit à installer.

Si votre installation d'origine ne comprenait pas de UpgradeCode, vous ne pourrez pas utiliser cette fonction.

Mike Dimmick
la source
21
Sans aucun doute, Mike sait exactement de quoi il parle, tout le respect que je lui dois, mais cela me fait désespérer de songer à encombrer mon esprit avec une solide compréhension de ce que fait Windows Installer. Avant de le savoir, je ferai des travaux de consultation Java et .NET pour les clients Enterprise dans les villes du centre technologique, au-delà du périphérique, remplissant mes rapports TPS et me demandant pourquoi la vie semble si vide. Je pense que mon prochain projet pourrait s'installer avec NSIS, qui malgré tous ses défauts, comme un langage absurde semblable à un assemblage, ne m'a pas fait comprendre ce que fait Windows Installer.
Jonathan Hartley
2
@Tartley - allez avec InnoSetup, cela vous sauvera le langage d'assemblage :) Assurez-vous de saisir IStool aussi, cela aide beaucoup. Aussi - convenu que pour des installations simples, tout cela est beaucoup trop compliqué, mais je pense qu'ils ont vraiment besoin de cette complexité pour installer quelque chose comme SQL Server 2008 ...
Roman Starkov
11

J'ai utilisé ce site pour m'aider à comprendre les bases de la mise à niveau WiX:

http://wix.tramontana.co.hu/tutorial/upgrades-and-modularization

Ensuite, j'ai créé un exemple d'installation, (installé un fichier de test), puis créé le programme d'installation de mise à niveau (installé 2 exemples de fichiers de test). Cela vous donnera une compréhension de base du fonctionnement du mécanisme.

Et comme Mike l'a dit dans le livre d'Apress, "Le guide définitif de Windows Installer", il vous aidera à comprendre, mais il n'est pas écrit en utilisant WiX.

Un autre site qui a été assez utile était celui-ci:

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

CheGueVerra
la source
L'exemple sur la page ne fonctionne pas comme prévu wix.tramontana.co.hu/tutorial/upgrades-and-modularization/… . J'ai joué avec. Il est même possible de rétrograder lorsque la page indique qu'elle sera interdite
sergtk
10

J'ai lu la documentation WiX , des exemples téléchargés, mais j'ai toujours eu beaucoup de problèmes avec les mises à niveau. Les mises à niveau mineures n'exécutent pas la désinstallation des produits précédents malgré la possibilité de spécifier ces désinstallations. J'ai passé plus d'une journée à enquêter et j'ai découvert que WiX 3.5 introduisait une nouvelle balise pour les mises à niveau. Voici l'utilisation:

<MajorUpgrade Schedule="afterInstallInitialize"
        DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit." 
        AllowDowngrades="no" />

Mais la principale raison des problèmes était que la documentation indique d'utiliser les paramètres " REINSTALL = ALL REINSTALLMODE = vomus " pour les mises à niveau mineures et petites, mais cela ne dit pas que ces paramètres sont INTERDITS pour les mises à niveau majeures - ils arrêtent simplement de fonctionner. Vous ne devez donc pas les utiliser avec des mises à niveau majeures.

Sasha
la source
7

Je suggère de jeter un œil au tutoriel d'Alex Shevchuk. Il explique «mise à niveau majeure» via WiX avec un bon exemple pratique de From MSI to WiX, Part 8 - Major Upgrade .

Faraz
la source
Merci pour le lien vers cet article ... c'est fantastique!
Robert P
7

Une chose importante que j'ai manquée dans les tutoriels pendant un certain temps (volée à http://www.tramontana.co.hu/wix/lesson4.php ) qui a entraîné les erreurs "Une autre version de ce produit est déjà installée":

* Les petites mises à jour signifient de petites modifications à un ou quelques fichiers où la modification ne justifie pas de changer la version du produit (major.minor.build). Vous n'avez pas non plus à modifier le GUID du produit. Notez que vous devez toujours modifier le GUID du package lorsque vous créez un nouveau fichier .msi qui est différent des précédents à tous égards. Le programme d'installation garde une trace de vos programmes installés et les trouve lorsque l'utilisateur souhaite modifier ou supprimer l'installation à l'aide de ces GUID. L'utilisation du même GUID pour différents packages confondra le programme d'installation.

Les mises à niveau mineures indiquent des changements où la version du produit changera déjà. Modifiez l'attribut Version de la balise Product. Le produit restera le même, vous n'avez donc pas besoin de changer le GUID du produit mais, bien sûr, obtenez un nouveau GUID de package.

Les mises à niveau majeures dénotent des changements importants comme le passage d'une version complète à une autre. Tout changer: attribut de version, GUID du produit et du package.

Daniel Morritt
la source
3
Package: Type d'ID: AutogenGuid description: GUID du code de package pour un produit ou un module de fusion. Lors de la compilation d'un produit, cet attribut ne doit pas être défini afin de permettre au code du package d'être généré pour chaque build. Lors de la compilation d'un module de fusion, cet attribut doit être défini sur le guide de modularisation. ---- nous n'avons donc pas besoin de faire attention à l'ID du paquet, non?
Cooper.Wu
Votre lien est mort
bam500
5

J'utilise la dernière version de WiX (3.0) et je n'ai pas pu faire fonctionner ce qui précède. Mais cela a fonctionné:

<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>

Notez que PUT-GUID-HERE doit être le même que le GUID que vous avez défini dans la propriété UpgradeCode du produit.

Merill Fernando
la source
2

Ci-dessous a fonctionné pour moi.

<Product Id="*" Name="XXXInstaller" Language="1033" Version="1.0.0.0" 
    Manufacturer="XXXX" UpgradeCode="YOUR_GUID_HERE">
<Package InstallerVersion="xxx" Compressed="yes"/>
<Upgrade Id="YOUR_GUID_HERE">
    <UpgradeVersion Property="REMOVINGTHEOLDVERSION" Minimum="1.0.0.0" 
        RemoveFeatures="ALL" />
</Upgrade>
<InstallExecuteSequence>
    <RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>

Veuillez vous assurer que le code de mise à niveau dans le produit correspond à l'ID dans la mise à niveau.

NishantJ
la source
1

C'est ce qui a fonctionné pour moi, même avec une note de DOWN importante :

<Wix ...>
  <Product ...>
    <Property Id="REINSTALLMODE" Value="amus" />
    <MajorUpgrade AllowDowngrades="yes" />
Gian Marco Gherardi
la source