¿Cómo implementar la actualización del instalador WiX?

233

En el trabajo usamos WiX para construir paquetes de instalación. Queremos que la instalación del producto X resulte en la desinstalación de la versión anterior de ese producto en esa máquina.

Leí en varios lugares de Internet acerca de una actualización importante, pero no pude hacer que funcione. ¿Alguien puede especificar los pasos exactos que debo seguir para agregar la función de desinstalación de la versión anterior a WiX?

Dror Helper
fuente

Respuestas:

189

En las versiones más recientes (de la versión beta 3.5.1315.0), puede usar el elemento MajorUpgrade en lugar de usar el suyo.

Por ejemplo, usamos este código para hacer actualizaciones automáticas. Evita las degradaciones, da un mensaje de error localizado y también evita la actualización de una versión idéntica ya existente (es decir, solo se actualizan las versiones inferiores):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />
Hormiga
fuente
8
La publicación de blog de Bob Arnson sobre esto proporciona mucha información agradable.
Dave Andersen
17
Nota: No está documentado en ningún lado, pero el <MajorUpgrade>elemento " " debe colocarse después <Package> . De lo contrario, candleda el siguiente error: "error CNDL0107: La validación del esquema falló con el siguiente error en la línea 1, columna 473: El elemento 'Producto' en el espacio de nombres ' schemas.microsoft.com/wix/2006/wi ' tiene un elemento hijo no válido ' MajorUpgrade 'en el espacio de nombres' schemas.microsoft.com/wix/2006/wi '. Lista de posibles elementos esperados:' Paquete '. ".
Rob W
21
+1 Esta respuesta necesita recibir tantos votos positivos como sea posible; Es muy tentador ir con una respuesta que tiene 5 veces más votos, pero utiliza enfoques más antiguos.
Lynn se desmorona
1
Buen punto. ¡He agregado un ejemplo para que la gente no lo ignore solo porque no tiene uno!
Ant
66
Solo quiero señalar que no necesita especificar AllowDowngradeso AllowSameVersionUpgrades. Por defecto ya no.
Luminoso
221

Finalmente encontré una solución: la estoy publicando aquí para otras personas que podrían tener el mismo problema (los 5):

  • Cambie la identificación del producto a *
  • Debajo del producto agregue lo siguiente:

    <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> 
  • En InstallExecuteSequence agregue:

    <RemoveExistingProducts Before="InstallInitialize" /> 

A partir de ahora, cada vez que instalo el producto, elimina las versiones instaladas anteriores.

Nota: reemplace el Id. De actualización con su propio GUID

Dror Helper
fuente
153
sí, aprender WiX es como tratar de descubrir los encantamientos oscuros que alguien decidió "tener sentido" para realizar una acción simple. Algo así como UNIX.
mmr
66
Además, ¿qué hace exactamente "Cambiar la identificación del producto a *"? ¿Genera un nuevo ID de producto cada vez? ¿Hay consecuencias de que su producto ya no tenga una identificación fija? - Suena como una exageración.
Anthony
10
@Antony, @Dror Helper: estoy bastante seguro de que no deberías usar "*" para generar un nuevo GUID aquí. El GUID interno (Id. De actualización = "") debe estar codificado y arreglado, y debe coincidir con el GUID en su atributo (Product UpgradeCode = "").
Jonathan Hartley
37
Creo que probablemente debería editar su ejemplo allí para NO tener un GUID real. Estoy seguro de que la gente copiará y pegará eso y lo usará literalmente. ¿Quizás use "SU-PRODUCTO-GUÍA-ACTUALIZACIÓN-CÓDIGO-AQUÍ"?
Marrón
12
Hay un error en tu ejemplo. MSI ProductVersionsolo admite tres campos de versión; por lo tanto, el cuarto campo no se comparará en absoluto. Consulte la nota en VersionMin y VersionMax en msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Sridhar Ratnakumar
89

El siguiente es el tipo de sintaxis que uso para las actualizaciones principales:

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

Como señaló @Brian Gillespie, hay otros lugares para programar RemoveExistingProducts según las optimizaciones deseadas. Tenga en cuenta que PUT-GUID-AQUÍ debe ser idéntico.

Rob Mensching
fuente
2
Estoy leyendo la sección "Actualización y parches" en el libro de Nick Ramirez sobre Wix aquí, y dice que si programa Eliminar productos existentes después de Instalar inicializar, también DEBE programar <InstallExecute After="RemoveExistingProducts" />. Su ejemplo no tiene esto, ¿eso significa que el libro está equivocado?
Wim Coenen
3
Nunca programo explícitamente InstallExecute.
Rob Mensching
1
Yo no. En WiX v3.6, Burn hará que las actualizaciones menores sean fáciles de ejecutar, pero sin Burn requiere la interacción manual del usuario (tiene que proporcionar opciones de línea de comandos) que hacen que las actualizaciones menores sean básicamente inútiles. :)
Rob Mensching 01 de
1
@RobMensching: ¿cómo se evita la instalación de una versión anterior sobre una nueva? Su respuesta funciona para mí (el único ejemplo de "actualización importante" que puedo compilar con WiX v3.5.2519.0), pero es posible instalar una versión anterior (después de eso, veo ambas versiones en "Agregar / Eliminar programas ").
Christian Specht
44
De acuerdo, acabo de encontrar el elemento MajorUpgrade en esta respuesta que hace exactamente lo que quiero, incluida la prevención de degradaciones.
Christian Specht
40

El elemento Actualizar dentro del elemento Producto, combinado con la programación adecuada de la acción, realizará la desinstalación que está buscando. Asegúrese de enumerar los códigos de actualización de todos los productos que desea eliminar.

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

Tenga en cuenta que, si tiene cuidado con sus compilaciones, puede evitar que las personas instalen accidentalmente una versión anterior de su producto sobre una nueva. Para eso está el campo Máximo. Cuando creamos instaladores, establecemos UpgradeVersion Maximum en la versión que se está construyendo, pero IncludeMaximum = "no" para evitar este escenario.

Tiene opciones con respecto a la programación de RemoveExistingProducts. Prefiero programarlo después de InstallFinalize (en lugar de después de InstallInitialize como otros lo han recomendado):

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

Esto deja instalada la versión anterior del producto hasta después de que se copian los nuevos archivos y claves de registro. Esto me permite migrar datos de la versión anterior a la nueva (por ejemplo, ha cambiado el almacenamiento de las preferencias del usuario del registro a un archivo XML, pero desea ser cortés y migrar su configuración). Esta migración se realiza en una acción personalizada diferida justo antes de InstallFinalize.

Otro beneficio es la eficiencia: si hay archivos sin cambios, Windows Installer no se molesta en copiarlos nuevamente cuando programa después de InstallFinalize. Si programa después de InstallInitialize, primero se elimina completamente la versión anterior y luego se instala la nueva versión. Esto da como resultado la eliminación innecesaria y la copia de archivos.

Para otras opciones de programación, vea el tema de ayuda RemoveExistingProducts en MSDN. Esta semana, el enlace es: http://msdn.microsoft.com/en-us/library/aa371197.aspx

Brian Gillespie
fuente
2
@Brian Gillespie: ¿qué significa "... si hay archivos sin cambios ..."? ¿Cuál es el criterio para que Windows Installer decida cuándo reemplazar un archivo, AssemblyVersion, AssemblyFileVersion, tamaño de archivo, ...?
donttellya
2
@donttellya +1 aprendió esto de la manera difícil. RemoveExistingProductsestaba programado para después InstallFinalizey los dlls no se actualizaban porque la versión de ensamblaje no se modificó, pero sí otros campos como AssemblyProduct. No quiero estar a merced de la rutina de comparación de archivos, solo quiero que la aplicación anterior se haya ido
wal
16

Tal vez sea mejor preguntar esto en la lista de correo de usuarios de WiX .

WiX se utiliza mejor con una comprensión firme de lo que está haciendo Windows Installer. Puede considerar obtener " La guía definitiva para el instalador de Windows ".

La acción que elimina un producto existente es la acción RemoveExistingProducts . Debido a que las consecuencias de lo que hace depende de dónde está programado, es decir, si una falla hace que el producto antiguo se reinstale y si los archivos no modificados se copian nuevamente, debe programarlo usted mismo.

RemoveExistingProductsprocesa <Upgrade>elementos en la instalación actual, haciendo coincidir el @Idatributo con el UpgradeCode(especificado en el <Product>elemento) de todos los productos instalados en el sistema. El UpgradeCodedefine una familia de productos relacionados. Se eliminarán todos los productos que tengan este UpgradeCode, cuyas versiones se encuentren dentro del rango especificado, y donde el UpgradeVersion/@OnlyDetectatributo esté no(o se omita).

La documentación para las RemoveExistingProductsmenciones que establecen la UPGRADINGPRODUCTCODEpropiedad. Significa que el proceso de desinstalación del producto que se elimina recibe esa propiedad, cuyo valor es elProduct/@Id del producto que se está instalando.

Si su instalación original no incluía un UpgradeCode, no podrá utilizar esta función.

Mike Dimmick
fuente
21
Sin duda, Mike sabe exactamente de qué está hablando, con el debido respeto, pero me da un suspiro de desesperación contemplar abarrotar mi mente con una comprensión firme de lo que está haciendo Windows Installer. Antes de darme cuenta, haré trabajos de consultoría Java y .NET para clientes de Enterprise en las ciudades de centros tecnológicos, más allá de la carretera de circunvalación, llenando mis informes de TPS y preguntándome por qué la vida parece tan vacía. Creo que mi próximo proyecto podría instalarse con NSIS, que a pesar de todas sus fallas, como un lenguaje ridículo como ensamblador, no me hizo comprender lo que está haciendo Windows Installer.
Jonathan Hartley
2
@Tartley - ve con InnoSetup, eso te ahorrará el lenguaje ensamblador :) Asegúrate de tomar IStool también, te ayuda mucho. Además, acordé que para instalaciones simples todo esto es demasiado complicado, pero creo que realmente necesitan esta complejidad para instalar algo como SQL Server 2008 ...
Roman Starkov
11

Usé este sitio para ayudarme a comprender los conceptos básicos sobre la actualización de WiX:

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

Luego creé un instalador de muestra (instalé un archivo de prueba), luego creé el instalador de actualización (instalé 2 archivos de prueba de muestra). Esto le dará una comprensión básica de cómo funciona el mecanismo.

Y como Mike dijo en el libro de Apress, "La guía definitiva para el instalador de Windows", le ayudará a comprender, pero no está escrito con WiX.

Otro sitio que fue bastante útil fue este:

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

CheGueVerra
fuente
El ejemplo en la página no funciona como se esperaba wix.tramontana.co.hu/tutorial/upgrades-and-modularization/… . Jugué con eso. Incluso es posible degradar cuando la página indica que estará prohibido
sergtk
10

Leí la documentación de WiX , descargué ejemplos, pero aún tuve muchos problemas con las actualizaciones. Las actualizaciones menores no ejecutan la desinstalación de los productos anteriores a pesar de la posibilidad de especificar esas desinstalaciones. Pasé más de un día en investigaciones y descubrí que WiX 3.5 introdujo una nueva etiqueta para las actualizaciones. Aquí está el uso:

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

Pero la razón principal de los problemas fue que la documentación dice que se deben usar los parámetros " REINSTALL = ALL REINSTALLMODE = vomus " para actualizaciones menores y pequeñas, pero no dice que esos parámetros estén PROHIBIDOS para actualizaciones importantes , simplemente dejan de funcionar. Por lo tanto, no debe usarlos con actualizaciones importantes.

Sasha
fuente
7

Una cosa importante que me perdí de los tutoriales por un tiempo (robado de http://www.tramontana.co.hu/wix/lesson4.php ) que resultó en los errores "Otra versión de este producto ya está instalada":

* Pequeñas actualizaciones significan pequeños cambios en uno o unos pocos archivos donde el cambio no garantiza cambiar la versión del producto (major.minor.build). Tampoco tiene que cambiar el GUID del producto. Tenga en cuenta que siempre debe cambiar el GUID del paquete cuando cree un nuevo archivo .msi que sea diferente de los anteriores en cualquier aspecto. El instalador realiza un seguimiento de sus programas instalados y los encuentra cuando el usuario desea cambiar o eliminar la instalación utilizando estos GUID. Usar el mismo GUID para diferentes paquetes confundirá al instalador.

Las actualizaciones menores indican cambios en los que la versión del producto ya cambiará. Modifique el atributo Versión de la etiqueta Producto. El producto seguirá siendo el mismo, por lo que no necesita cambiar el GUID del producto sino, por supuesto, obtener un nuevo GUID del paquete.

Las actualizaciones importantes denotan cambios significativos, como pasar de una versión completa a otra. Cambie todo: atributo de versión, GUID de producto y paquete.

Daniel Morritt
fuente
3
Paquete: Tipo de identificación: AutogenGuid descripción: El GUID del código del paquete para un producto o módulo de fusión. Al compilar un producto, este atributo no debe establecerse para permitir que se genere el código del paquete para cada compilación. Al compilar un módulo de combinación, este atributo debe establecerse en la guía de modularización. ---- así que no necesitamos prestar atención a la identificación del paquete, ¿verdad?
Cooper.Wu
Su enlace está muerto
bam500
5

Estoy usando la última versión de WiX (3.0) y no pude hacer funcionar lo anterior. Pero esto funcionó:

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

Tenga en cuenta que PUT-GUID-AQUÍ debe ser el mismo que el GUID que ha definido en la propiedad UpgradeCode del Producto.

Merill Fernando
fuente
2

A continuación funcionó para mí.

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

Asegúrese de que el Código de actualización en el producto coincida con el ID en la actualización.

NishantJ
fuente
1

Esto es lo que funcionó para mí, incluso con un grado DOWN importante :

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