Como implementar a atualização do instalador do WiX?

233

No trabalho, usamos o WiX para criar pacotes de instalação. Queremos que a instalação do produto X resulte na desinstalação da versão anterior desse produto nessa máquina.

Eu li em vários lugares na Internet sobre uma grande atualização, mas não consegui fazê-la funcionar. Alguém pode especificar as etapas exatas que preciso executar para adicionar o recurso de desinstalação da versão anterior ao WiX?

Dror Helper
fonte

Respostas:

189

Nas versões mais recentes (da versão 3.5.1315.0 beta), você pode usar o elemento MajorUpgrade em vez de usar o seu próprio.

Por exemplo, usamos esse código para fazer atualizações automáticas. Impede downgrades, fornecendo uma mensagem de erro localizada, e também impede a atualização de uma versão idêntica já existente (ou seja, apenas as versões inferiores são atualizadas):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />
Formiga
fonte
8
A publicação no blog de Bob Arnson sobre isso fornece muitas informações interessantes.
Dave Andersen
17
Nota: Não documentado em nenhum lugar, mas o <MajorUpgrade>elemento " " deve ser colocado depois <Package> . Caso contrário, candleocorrerá o seguinte erro: "erro CNDL0107: a validação do esquema falhou com o seguinte erro na linha 1, coluna 473: O elemento 'Produto' no espaço de nome ' schemas.microsoft.com/wix/2006/wi ' possui um elemento filho inválido ' MajorUpgrade 'no espaço de nome' schemas.microsoft.com/wix/2006/wi '. Lista de possíveis elementos esperados:' Pacote '. ".
Rob W
21
+1 Esta resposta precisa receber o maior número possível de votos; é muito tentador usar uma resposta que tenha 5x os votos positivos, mas usa abordagens mais antigas.
Lynn desintegração
1
Bom ponto. Eu adicionei um exemplo para que as pessoas não o ignorem apenas porque ele não possui um!
Ant
6
Só quero salientar que você não precisa especificar AllowDowngradesou AllowSameVersionUpgrades. Eles assumem o padrão já não.
Luminous
221

Finalmente, encontrei uma solução - estou postando aqui para outras pessoas que podem ter o mesmo problema (todos os 5):

  • Altere o ID do produto para *
  • Em produto, adicione o seguinte:

    <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> 
    
  • Em InstallExecuteSequence, adicione:

    <RemoveExistingProducts Before="InstallInitialize" /> 

A partir de agora, sempre que instalo o produto, ele removeu as versões instaladas anteriores.

Nota: substitua o ID da atualização pelo seu próprio GUID

Dror Helper
fonte
153
sim, aprender WiX é como tentar descobrir os encantamentos obscuros que alguém decidiu "fazer sentido" para executar uma ação simples. Mais ou menos como o UNIX.
MMR
6
Além disso, o que exatamente "Alterar o ID do produto para *" faz? Ele gera um novo ID de produto a cada vez? Há consequências para o seu produto não ter mais um ID fixo? - parece exagero.
Anthony
10
@Antony, @Dror Helper: Tenho certeza que você não deve usar "*" para gerar um novo GUID aqui. O GUID interno (Upgrade Id = "") deve ser codificado e corrigido e deve corresponder ao GUID no seu atributo (Product UpgradeCode = "").
23139 Jonathan Hartley
37
Acho que você provavelmente deve editar seu exemplo para NÃO ter um GUID real. Tenho certeza que as pessoas vão copiar e colar e usá-lo literalmente. Talvez use "O SEU PRODUTO-UPGRADECODE-GUID-AQUI"?
Brown
12
Há um erro no seu exemplo. MSI's ProductVersionsuporta apenas três campos de versão; portanto, o quarto campo não será comparado. Consulte a observação em VersionMin e VersionMax em msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Sridhar Ratnakumar
89

A seguir, é apresentado o tipo de sintaxe que eu uso para grandes atualizações:

<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 @Brian Gillespie observou, há outros locais para agendar os RemoveExistingProducts, dependendo das otimizações desejadas. Observe que PUT-GUID-HERE deve ser idêntico.

Rob Mensching
fonte
2
Estou lendo a seção "Atualizando e corrigindo" no livro de Nick Ramirez no Wix aqui, e ele afirma que se você agendar RemoveExistingProducts após InstallInitialize, também DEVE agendar <InstallExecute After="RemoveExistingProducts" />. Seu exemplo não tem isso - isso significa que o livro está errado?
Wim Coenen
3
Eu nunca planejo explicitamente o InstallExecute.
precisa
1
Eu não. No WiX v3.6, o Burn facilitará pequenas atualizações, mas sem o Burn, ele precisará de interação manual do usuário (precisará fornecer opções de linha de comando), o que torna as atualizações secundárias basicamente inúteis. :)
Rob Mensching
1
@RobMensching: como evitar a instalação de uma versão mais antiga sobre uma mais nova? Sua resposta funciona para mim (o único exemplo de "grande atualização" que posso compilar com o WiX v3.5.2519.0), mas é possível instalar uma versão mais antiga (depois disso, vejo as duas versões em "Adicionar / Remover programas ").
Christian Specht 29/11
4
Ok, eu só descobri o elemento MajorUpgrade em esta resposta que faz exatamente o que eu quero, incluindo rebaixamentos impedindo.
Christian Specht 29/11
40

O elemento Upgrade dentro do elemento Product, combinado com o planejamento adequado da ação, executará a desinstalação que você procura. Certifique-se de listar os códigos de atualização de todos os produtos que você deseja remover.

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

Observe que, se você for cuidadoso com suas compilações, poderá impedir que as pessoas instalem acidentalmente uma versão mais antiga do seu produto sobre uma mais nova. É para isso que serve o campo Máximo. Quando criamos instaladores, configuramos UpgradeVersion Maximum para a versão que está sendo criada, mas IncludeMaximum = "no" para evitar esse cenário.

Você tem opções sobre o agendamento de RemoveExistingProducts. Prefiro agendá-lo após o InstallFinalize (em vez de depois do InstallInitialize, como outros recomendaram):

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

Isso deixa a versão anterior do produto instalada até que os novos arquivos e chaves do registro sejam copiados. Isso permite migrar dados da versão antiga para a nova (por exemplo, você alterou o armazenamento das preferências do usuário do registro para um arquivo XML, mas deseja ser educado e migrar as configurações). Essa migração é feita em uma ação personalizada adiada imediatamente antes do InstallFinalize.

Outro benefício é a eficiência: se houver arquivos inalterados, o Windows Installer não se preocupará em copiá-los novamente quando você agendar após o InstallFinalize. Se você agendar após o InstallInitialize, a versão anterior será completamente removida primeiro e, em seguida, a nova versão será instalada. Isso resulta em exclusão e nova cópia desnecessárias de arquivos.

Para outras opções de agendamento, consulte o tópico da ajuda RemoveExistingProducts no MSDN. Esta semana, o link é: http://msdn.microsoft.com/en-us/library/aa371197.aspx

Brian Gillespie
fonte
2
@ Brian Gillespie: o que significa "... se houver arquivos inalterados ..."? Quais são os critérios para o Windows Installer decidir quando substituir um arquivo, AssemblyVersion, AssemblyFileVersion, tamanho do arquivo, ...?
Donttellya 21/05
2
@donttellya +1 aprendeu isso da maneira mais difícil. RemoveExistingProductsfoi programado para depois InstallFinalizee as dlls não estavam sendo atualizadas porque o assemblyVersion não foi alterado, mas outros campos como AssemblyProduct foram. Eu não quero estar à mercê da rotina de comparação de arquivos - eu só quero o aplicativo anterior GONE #
18/02/15
16

Você pode perguntar melhor isso na lista de discussão dos usuários do WiX .

O WiX é melhor usado com um entendimento firme do que o Windows Installer está fazendo. Você pode considerar obter " O Guia Definitivo do Windows Installer ".

A ação que remove um produto existente é a ação RemoveExistingProducts . Como as consequências do que ele faz depende de onde está agendado - a saber, se uma falha faz com que o produto antigo seja reinstalado e se os arquivos inalterados são copiados novamente - você precisa agendá-lo.

RemoveExistingProductsprocessa <Upgrade>elementos na instalação atual, correspondendo o @Idatributo ao UpgradeCode(especificado no <Product>elemento) de todos os produtos instalados no sistema. O UpgradeCodedefine uma família de produtos relacionados. Quaisquer produtos que tenham esse UpgradeCode, cujas versões se enquadram no intervalo especificado e onde o UpgradeVersion/@OnlyDetectatributo esteja no(ou seja omitido), serão removidos.

A documentação para RemoveExistingProductsmenções à configuração da UPGRADINGPRODUCTCODEpropriedade. Isso significa que o processo de desinstalação do produto que está sendo removido recebe essa propriedade, cujo valor é o Product/@Iddo produto que está sendo instalado.

Se a sua instalação original não incluiu um UpgradeCode, você não poderá usar esse recurso.

Mike Dimmick
fonte
21
Sem dúvida, Mike sabe exatamente do que está falando, com todo o respeito, mas me faz suspirar de desespero contemplar atravancando minha mente com uma firme compreensão do que o Windows Installer está fazendo. Antes que eu perceba, farei trabalhos de consultoria em Java e .NET para clientes Enterprise nas cidades do centro de tecnologia, além do caminho, preenchendo meus relatórios TPS e me perguntando por que a vida parece tão vazia. Acho que meu próximo projeto pode ser instalado com o NSIS, que, apesar de todas as suas falhas, como uma linguagem absurda como uma montagem, não me fez entender o que o Windows Installer está fazendo.
23139 Jonathan Hartley
2
@Tartley - vá com o InnoSetup, que salvará a linguagem do assembly :) Certifique-se de pegar o IStool também, isso ajuda muito. Também - concordaram que para simples instala tudo isso é muito complicado, mas acho que eles realmente precisam dessa complexidade para instalar algo como SQL Server 2008 ...
Roman Starkov
11

Usei este site para me ajudar a entender o básico sobre o WiX Upgrade:

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

Depois, criei um instalador de amostra (instalei um arquivo de teste) e depois criei o instalador de atualização (instalei 2 arquivos de teste de amostra). Isso lhe dará uma compreensão básica de como o mecanismo funciona.

E, como Mike disse no livro da Apress, "O Guia Definitivo do Windows Installer", ele ajudará você a entender, mas não foi escrito usando o WiX.

Outro site que foi bastante útil foi este:

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

CheGueVerra
fonte
O exemplo na página não funciona conforme o esperado wix.tramontana.co.hu/tutorial/upgrades-and-modularization/… . Eu brinquei com isso. É ainda possível fazer o downgrade quando a página afirma que será proibido
sergtk
10

Eu li a documentação do WiX , baixei exemplos, mas ainda tinha muitos problemas com atualizações. Atualizações menores não executam a desinstalação dos produtos anteriores, apesar da possibilidade de especificar essas desinstalações. Passei mais de um dia em investigações e descobri que o WiX 3.5 introduziu uma nova tag para atualizações. Aqui está o uso:

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

Mas a principal razão dos problemas foi que a documentação diz para usar os parâmetros " REINSTALL = ALL REINSTALLMODE = vomus " para pequenas e pequenas atualizações, mas não diz que esses parâmetros são PROIBIDOS para grandes atualizações - eles simplesmente param de funcionar. Portanto, você não deve usá-los com grandes atualizações.

Sasha
fonte
7

Eu sugeriria dar uma olhada no tutorial de Alex Shevchuk. Ele explica a "grande atualização" através do WiX com um bom exemplo prático de From MSI to WiX, Part 8 - Major Upgrade .

Faraz
fonte
Obrigado pelo link para esse artigo ... é fantástico!
Robert P
7

Uma coisa importante que perdi dos tutoriais por um tempo (roubada de http://www.tramontana.co.hu/wix/lesson4.php ) que resultou nos erros "Outra versão deste produto já está instalada":

* Pequenas atualizações significam pequenas alterações em um ou alguns arquivos nos quais a alteração não garante a alteração da versão do produto (major.minor.build). Você também não precisa alterar o GUID do produto. Observe que você sempre deve alterar o GUID do pacote ao criar um novo arquivo .msi diferente dos anteriores em qualquer aspecto. O instalador controla os programas instalados e os encontra quando o usuário deseja alterar ou remover a instalação usando esses GUIDs. Usar o mesmo GUID para pacotes diferentes confundirá o instalador.

Pequenas atualizações indicam mudanças nas quais a versão do produto já será alterada. Modifique o atributo Version da tag Product. O produto permanecerá o mesmo; portanto, você não precisa alterar o GUID do produto, mas, é claro, obter um novo GUID do pacote.

Grandes atualizações indicam mudanças significativas, como passar de uma versão completa para outra. Alterar tudo: atributo de versão, GUIDs de produtos e pacotes.

Daniel Morritt
fonte
3
Pacote: tipo de ID: AutogenGuid descrição: o GUID do código do pacote para um produto ou módulo de mesclagem. Ao compilar um produto, esse atributo não deve ser definido para permitir que o código do pacote seja gerado para cada construção. Ao compilar um módulo de mesclagem, esse atributo deve ser definido como o guia de modularização. ---- então não precisamos prestar atenção na identificação do pacote, certo?
Cooper.Wu
O seu link está morto
bam500 22/02
5

Estou usando a versão mais recente do WiX (3.0) e não consegui fazer o trabalho acima. Mas isso funcionou:

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

Observe que PUT-GUID-HERE deve ser igual ao GUID que você definiu na propriedade UpgradeCode do Produto.

Merill Fernando
fonte
2

Abaixo funcionou para mim.

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

Certifique-se de que o UpgradeCode no produto corresponda ao ID na atualização.

NishantJ
fonte
1

Isto é o que funcionou para mim, mesmo com as principais notas DOWN :

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