Come implementare l'aggiornamento del programma di installazione WiX?


233

Al lavoro utilizziamo WiX per creare pacchetti di installazione. Vogliamo che l'installazione del prodotto X comporti la disinstallazione della versione precedente di quel prodotto su quella macchina.

Ho letto su diversi punti su Internet un aggiornamento importante, ma non sono riuscito a farlo funzionare. Qualcuno può specificare i passaggi esatti che devo prendere per aggiungere la funzionalità di disinstallazione della versione precedente a WiX?

Risposte:


189

Nelle versioni più recenti (dalla versione 3.5.1315.0 beta), puoi utilizzare l' elemento MajorUpgrade invece di utilizzare il tuo.

Ad esempio, utilizziamo questo codice per eseguire aggiornamenti automatici. Impedisce il downgrade, fornendo un messaggio di errore localizzato e impedisce anche l'aggiornamento di una versione identica già esistente (ovvero vengono aggiornate solo le versioni inferiori):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />

8
Il post sul blog di Bob Arnson su questo fornisce molte belle informazioni.
Dave Andersen,

17
Nota: non documentato da nessuna parte, ma l' <MajorUpgrade>elemento " " deve essere posizionato dopo <Package> . In caso contrario, candleviene visualizzato il seguente errore: "errore CNDL0107: convalida dello schema non riuscita con il seguente errore alla riga 1, colonna 473: L'elemento 'Prodotto' nello spazio dei nomi ' schemas.microsoft.com/wix/2006/wi ' ha un elemento figlio non valido ' Aggiornamento principale "nello spazio dei nomi" schemas.microsoft.com/wix/2006/wi ". Elenco dei possibili elementi previsti:" Pacchetto ".".
Rob W,

21
+1 Questa risposta deve ricevere il maggior numero di voti possibile; è molto allettante seguire una risposta che ha 5 volte i voti positivi, ma utilizza approcci più vecchi.
Lynn che si sbriciola il

1
Buon punto. Ho aggiunto un esempio in modo che le persone non lo ignorino solo perché non ne ha uno!
Formica,

6
Voglio solo sottolineare che non è necessario specificare AllowDowngradeso AllowSameVersionUpgrades. Di default non lo sono già.
Luminoso

221

Alla fine ho trovato una soluzione - la sto pubblicando qui per altre persone che potrebbero avere lo stesso problema (tutti e 5 voi):

  • Cambia l'ID prodotto in *
  • Sotto prodotto aggiungere quanto segue:

    <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> 
  • In InstallExecuteSequence aggiungi:

    <RemoveExistingProducts Before="InstallInitialize" /> 

Da ora in poi ogni volta che installo il prodotto rimuovevano le versioni installate precedenti.

Nota: sostituire l'ID di aggiornamento con il proprio GUID


153
sì, imparare WiX è come cercare di capire gli oscuri incantesimi che qualcuno ha deciso di 'avere senso' per eseguire una semplice azione. Un po 'come UNIX.
mmr

6
Inoltre, cosa fa esattamente "Cambia l'ID prodotto in *"? Genera un nuovo ID prodotto ogni volta? Ci sono conseguenze per il tuo prodotto che non ha più un ID fisso? - sembra eccessivo.
Anthony,

10
@Antony, @Dror Helper: Sono abbastanza sicuro che non dovresti usare "*" per generare un nuovo GUID qui. Il GUID all'interno (ID aggiornamento = "") deve essere codificato e corretto e deve corrispondere al GUID nell'attributo (Product UpgradeCode = "").
Jonathan Hartley,

37
Penso che dovresti probabilmente modificare il tuo esempio lì per NON avere un vero GUID. Sono sicuro che la gente lo copia e incolla e lo userà alla lettera. Forse usi "IL TUO PRODOTTO-UPGRADECODE-GUID-QUI"?
Brown,

12
C'è un bug nel tuo esempio. MSI ProductVersionsupporta solo tre campi versione; pertanto il quarto campo non verrà affatto confrontato. Vedi la nota in VersionMin e VersionMax in msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Sridhar Ratnakumar,

89

Di seguito è riportato il tipo di sintassi che utilizzo per gli aggiornamenti principali:

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

Come notato da @Brian Gillespie, ci sono altri posti dove pianificare i prodotti RemoveExisting in base alle ottimizzazioni desiderate. Nota PUT-GUID-HERE deve essere identico.


2
Sto leggendo la sezione "Aggiornamento e patching" nel libro di Nick Ramirez su Wix qui, e afferma che se pianifichi RemoveExistingProducts dopo InstallInitialize, DEVI anche pianificare <InstallExecute After="RemoveExistingProducts" />. Il tuo esempio non ha questo: significa che il libro è sbagliato?
Wim Coenen,

3
Non ho mai programmato esplicitamente InstallExecute.
Rob Mensching il

1
Io non. In WiX v3.6, Burn renderà più semplici gli aggiornamenti minori ma senza Burn richiede l'interazione manuale da parte dell'utente (è necessario fornire opzioni da riga di comando) che rendono sostanzialmente inutili gli aggiornamenti minori. :)
Rob Mensching,

1
@RobMensching: come evitare l'installazione di una versione precedente su una più nuova? La tua risposta funziona per me (l'unico esempio di "aggiornamento importante" che posso arrivare a compilare con WiX v3.5.2519.0), ma è possibile installare una versione precedente (dopo ciò, vedo entrambe le versioni in "Aggiungi / Rimuovi programmi ").
Christian Specht,

4
Ok, ho appena trovato l' elemento MajorUpgrade in questa risposta che fa esattamente quello che voglio, inclusa la prevenzione dei downgrade.
Christian Specht,

40

L'elemento Upgrade all'interno dell'elemento Product, combinato con la corretta pianificazione dell'azione, eseguirà la disinstallazione che stai cercando. Assicurati di elencare i codici di aggiornamento di tutti i prodotti che desideri rimuovere.

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

Nota che, se stai attento con le tue build, puoi impedire alle persone di installare accidentalmente una versione precedente del tuo prodotto su una più nuova. Ecco a cosa serve il campo Massimo. Quando realizziamo i programmi di installazione, impostiamo UpgradeVersion Maximum sulla versione in fase di creazione, ma IncludeMaximum = "no" per impedire questo scenario.

Sono disponibili opzioni relative alla pianificazione di RemoveExistingProducts. Preferisco programmarlo dopo InstallFinalize (piuttosto che dopo InstallInitialize come altri hanno raccomandato):

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

Ciò lascia installata la versione precedente del prodotto fino a quando non vengono copiati i nuovi file e le chiavi di registro. Questo mi consente di migrare i dati dalla vecchia versione alla nuova (ad esempio, hai cambiato l'archiviazione delle preferenze dell'utente dal registro in un file XML, ma vuoi essere educato e migrare le loro impostazioni). Questa migrazione viene eseguita in un'azione personalizzata posticipata appena prima di InstallFinalize.

Un altro vantaggio è l'efficienza: se ci sono file invariati, Windows Installer non si preoccupa di copiarli di nuovo quando si pianifica dopo InstallFinalize. Se si pianifica dopo InstallInitialize, la versione precedente viene completamente rimossa per prima, quindi viene installata la nuova versione. Ciò comporta la cancellazione e la ricopiatura inutili dei file.

Per altre opzioni di pianificazione, consultare l'argomento della guida di RemoveExistingProducts in MSDN. Questa settimana, il link è: http://msdn.microsoft.com/en-us/library/aa371197.aspx


2
@Brian Gillespie: cosa significa "... se ci sono file invariati ..."? Quali sono i criteri per Windows Installer per decidere quando sostituire un file, AssemblyVersion, AssemblyFileVersion, dimensione del file, ...?
donttellya,

2
@donttellya +1 l'ha imparato nel modo più duro. RemoveExistingProductsera programmato per dopo InstallFinalizee le dll non venivano aggiornate poiché assemblyVersion era invariato ma altri campi come AssemblyProduct lo erano. Non voglio essere in balia della routine di confronto dei file - voglio solo l'app precedente ANDATA
wal

16

Potrebbe essere meglio chiedere questo sulla mailing list degli utenti WiX .

WiX viene utilizzato al meglio con una solida conoscenza di ciò che Windows Installer sta facendo. Potresti prendere in considerazione l'idea di ottenere " La guida definitiva a Windows Installer ".

L'azione che rimuove un prodotto esistente è l' azione RemoveExistingProducts . Poiché le conseguenze di ciò che fa dipendono da dove è pianificato, ovvero se un errore provoca la reinstallazione del vecchio prodotto e se i file invariati vengono copiati di nuovo, è necessario pianificarlo da soli.

RemoveExistingProductselabora gli <Upgrade>elementi nell'installazione corrente, abbinando l' @Idattributo al UpgradeCode(specificato <Product>nell'elemento) di tutti i prodotti installati sul sistema. La UpgradeCodedefinisce una famiglia di prodotti correlati. Tutti i prodotti che dispongono di questo UpgradeCode, le cui versioni rientrano nell'intervallo specificato e in cui l' UpgradeVersion/@OnlyDetectattributo è no(o omesso), verranno rimossi.

La documentazione per le RemoveExistingProductsmenzioni sull'impostazione della UPGRADINGPRODUCTCODEproprietà. Significa che il processo di disinstallazione per il prodotto che viene rimosso riceve quella proprietà, il cui valore è il Product/@Idper il prodotto che viene installato.

Se l'installazione originale non include un UpgradeCode, non sarà possibile utilizzare questa funzione.


21
Senza dubbio Mike sa esattamente di cosa sta parlando, con tutto il rispetto, ma mi fa sospirare dalla disperazione contemplare di ingombrare la mia mente con una ferma comprensione di ciò che Windows Installer sta facendo. Prima che io lo sappia, svolgerò lavori di consulenza Java e .NET ai clienti Enterprise nelle straordinarie città del centro tecnologico, oltre la circonvallazione, riempiendo i miei rapporti TPS e mi chiederò perché la vita sembra così vuota. Penso che il mio prossimo progetto potrebbe essere installato con NSIS, che per tutti i suoi difetti, come un linguaggio assurdo simile ad un assembly, non mi ha fatto capire cosa sta facendo Windows Installer.
Jonathan Hartley,

2
@Tartley - vai con InnoSetup, che ti salverà il linguaggio simile ad un assembly :) Assicurati di prendere anche IStool, aiuta molto. Inoltre - ha convenuto che per installazioni semplici tutto ciò è troppo complicato, ma penso che abbiano davvero bisogno di questa complessità per installare qualcosa come SQL Server 2008 ...
Roman Starkov

11

Ho usato questo sito per aiutarmi a capire le basi dell'aggiornamento WiX:

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

Successivamente ho creato un programma di installazione di esempio, (installato un file di prova), quindi ho creato il programma di installazione di aggiornamento (installato 2 file di prova di esempio). Questo ti darà una comprensione di base di come funziona il meccanismo.

E come ha detto Mike nel libro di Apress, "La guida definitiva a Windows Installer", ti aiuterà a capire, ma non è scritto usando WiX.

Un altro sito che è stato molto utile è stato questo:

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


L'esempio nella pagina non funziona come previsto wix.tramontana.co.hu/tutorial/upgrades-and-modularization/… . Ci ho giocato. È anche possibile effettuare il downgrade quando la pagina afferma che sarà proibito
sergtk

10

Ho letto la documentazione WiX , scaricato esempi, ma ho ancora avuto molti problemi con gli aggiornamenti. Gli aggiornamenti minori non eseguono la disinstallazione dei prodotti precedenti nonostante la possibilità di specificarli. Ho trascorso più di un giorno per le indagini e ho scoperto che WiX 3.5 ha introdotto un nuovo tag per gli aggiornamenti. Ecco l'uso:

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

Ma il motivo principale dei problemi è che la documentazione afferma di utilizzare i parametri " REINSTALL = ALL REINSTALLMODE = vomus " per gli aggiornamenti minori e piccoli, ma non dice che quei parametri sono VIETATI per gli aggiornamenti principali - semplicemente smettono di funzionare. Quindi non dovresti usarli con importanti aggiornamenti.



7

Una cosa importante che mi mancava dai tutorial per un po '(rubato da http://www.tramontana.co.hu/wix/lesson4.php ) che ha provocato gli errori "Un'altra versione di questo prodotto è già installata":

* Piccoli aggiornamenti significano piccole modifiche a uno o pochi file in cui la modifica non garantisce la modifica della versione del prodotto (major.minor.build). Non è necessario modificare nemmeno il GUID del prodotto. Si noti che è sempre necessario modificare il GUID del pacchetto quando si crea un nuovo file con estensione msi diverso da quelli precedenti sotto qualsiasi aspetto. Il programma di installazione tiene traccia dei programmi installati e li trova quando l'utente desidera modificare o rimuovere l'installazione utilizzando questi GUID. L'uso dello stesso GUID per pacchetti diversi confonderà il programma di installazione.

Piccoli aggiornamenti indicano cambiamenti in cui la versione del prodotto cambierà già. Modifica l'attributo Version del tag Product. Il prodotto rimarrà lo stesso, quindi non è necessario modificare il GUID del prodotto ma, ovviamente, ottenere un nuovo GUID del pacchetto.

Gli aggiornamenti importanti indicano cambiamenti significativi come passare da una versione completa all'altra. Cambia tutto: attributo versione, GUID prodotto e pacchetto.


3
Pacchetto: Tipo ID: AutogenGuid descrizione: GUID del codice pacchetto per un prodotto o modulo di unione. Durante la compilazione di un prodotto, questo attributo non deve essere impostato per consentire la generazione del codice del pacchetto per ogni build. Quando si compila un modulo di unione, questo attributo deve essere impostato sulla guida alla modularizzazione. ---- Quindi non abbiamo bisogno di prestare attenzione all'ID del pacchetto, giusto?
Cooper.Wu

Il tuo link è morto
bam500

5

Sto usando l'ultima versione di WiX (3.0) e non riesco a far funzionare quanto sopra. Ma questo ha funzionato:

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

Si noti che PUT-GUID-HERE dovrebbe essere uguale al GUID definito nella proprietà UpgradeCode del prodotto.


2

Di seguito ha funzionato per me.

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

Assicurati che UpgradeCode nel prodotto corrisponda all'ID in Upgrade.


1

Questo è ciò che ha funzionato per me, anche con i principali voti DOWN :

<Wix ...>
  <Product ...>
    <Property Id="REINSTALLMODE" Value="amus" />
    <MajorUpgrade AllowDowngrades="yes" />
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.