Jak wdrożyć aktualizację instalatora WiX?

233

W pracy używamy WiX do budowania pakietów instalacyjnych. Chcemy, aby instalacja produktu X spowodowała odinstalowanie poprzedniej wersji tego produktu na tym komputerze.

Czytałem w kilku miejscach w Internecie o dużym uaktualnieniu, ale nie mogłem go uruchomić. Czy ktoś może podać dokładne kroki, które muszę wykonać, aby dodać funkcję odinstalowania poprzedniej wersji do WiX?

Dror Helper
źródło

Odpowiedzi:

189

W najnowszych wersjach (z wersji beta 3.5.1315.0) możesz używać elementu MajorUpgrade zamiast własnego.

Na przykład używamy tego kodu do automatycznych aktualizacji. Zapobiega obniżeniu wersji, wyświetla lokalny komunikat o błędzie, a także zapobiega uaktualnianiu już istniejącej identycznej wersji (tj. Uaktualniane są tylko wersje niższe):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />
Mrówka
źródło
8
Wpis na blogu Boba Arnsona na ten temat zawiera wiele fajnych informacji.
Dave Andersen
17
Uwaga: Nigdzie nie udokumentowane, ale element „ <MajorUpgrade>” należy umieścić po <Package> . W przeciwnym razie candlepojawia się następujący błąd: „błąd CNDL0107: Sprawdzanie poprawności schematu nie powiodło się z następującym błędem w wierszu 1, kolumna 473: Element„ Produkt ”w przestrzeni nazw„ schemas.microsoft.com/wix/2006/wi ”ma nieprawidłowy element potomny” MajorUpgrade „in namespace” schemas.microsoft.com/wix/2006/wi ”. Spodziewana lista możliwych elementów:„ Package ”.”.
Rob W
21
+1 Ta odpowiedź musi otrzymać jak najwięcej głosów poparcia; bardzo kusząca jest odpowiedź, która ma 5-krotnie wyższe głosy, ale używa starszych podejść.
Lynn Crumbling
1
Słuszna uwaga. Dodałem przykład, aby ludzie go nie ignorowali tylko dlatego, że nie ma!
Ant
6
Chcę tylko zaznaczyć, że nie musisz określać AllowDowngradesani AllowSameVersionUpgrades. Domyślnie już nie.
Luminous
221

Wreszcie znalazłem rozwiązanie - zamieszczam je tutaj dla innych osób, które mogą mieć ten sam problem (wszyscy 5 z was):

  • Zmień identyfikator produktu na *
  • W ramach produktu dodaj:

    <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> 
  • W obszarze InstallExecuteSequence dodaj:

    <RemoveExistingProducts Before="InstallInitialize" /> 

Od teraz, kiedy instaluję produkt, usuwałem poprzednie zainstalowane wersje.

Uwaga: zastąp identyfikator aktualizacji własnym identyfikatorem GUID

Dror Helper
źródło
153
tak, nauka WiX jest jak próba rozgryzienia niejasnych zaklęć, które ktoś uznał za „sensowne” do wykonania prostej czynności. Coś jak UNIX.
mmr
6
Co dokładnie robi „Zmień identyfikator produktu na *”? Czy za każdym razem generuje nowy identyfikator produktu? Czy są konsekwencje, że Twój produkt nie ma już ustalonego identyfikatora? - Brzmi jak przesada.
Anthony
10
@Antony, @Dror Helper: Jestem pewien, że nie powinieneś używać „*” do generowania nowego GUID tutaj. Identyfikator GUID w środku (identyfikator aktualizacji = "") powinien być na stałe zakodowany i powinien być zgodny z identyfikatorem GUID w atrybucie (Product UpgradeCode = "").
Jonathan Hartley
37
Myślę, że powinieneś prawdopodobnie edytować swój przykład, aby NIE mieć rzeczywistego identyfikatora GUID. Jestem pewien, że ludzie skopiują i wkleją to i użyją tego dosłownie. Może użyć „TWOJEGO PRODUKTU-UAKTUALNIJ-KOD-GUID-TUTAJ”?
Brown
12
W twoim przykładzie jest błąd. MSI ProductVersionobsługuje tylko trzy pola wersji; dlatego czwarte pole nie będzie w ogóle porównywane. Zobacz uwagę pod VersionMin i VersionMax w msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Sridhar Ratnakumar
89

Oto rodzaj składni, której używam do głównych aktualizacji:

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

Jak zauważył @Brian Gillespie, istnieją inne miejsca do zaplanowania RemoveExistingProducts w zależności od pożądanych optymalizacji. Uwaga: PUT-GUID-HERE musi być identyczny.

Rob Mensching
źródło
2
Czytam sekcję „Aktualizacja i łatanie” w książce Nicka Ramireza o Wix tutaj, a on stwierdza, że ​​jeśli zaplanujesz RemoveExistingProducts po InstallInitialize, MUSISZ także zaplanować <InstallExecute After="RemoveExistingProducts" />. Twój przykład tego nie ma - czy to znaczy, że książka jest zła?
Wim Coenen,
3
Nigdy nie planuję wyraźnie InstallExecute.
Rob Mensching
1
Ja nie. W WiX v3.6 Burn sprawi, że drobne uaktualnienia będą łatwe do wykonania, ale bez Burn wymaga ręcznej interakcji użytkownika (trzeba podać opcje wiersza poleceń), co sprawia, że ​​drobne uaktualnienia są w zasadzie bezużyteczne. :)
Rob
1
@RobMensching: jak uniknąć instalacji starszej wersji na nowszej? Twoja odpowiedź działa dla mnie (jedyny przykład „ważnej aktualizacji”, który mogę w ogóle skompilować z WiX v3.5.2519.0), ale możliwe jest zainstalowanie starszej wersji (potem widzę obie wersje w „Dodaj / Usuń programy ”).
Christian Specht
4
Ok, właśnie znalazłem element MajorUpgrade w tej odpowiedzi, który robi dokładnie to, czego chcę, w tym zapobiega obniżeniu wersji.
Christian Specht
40

Element aktualizacji w elemencie produktu w połączeniu z odpowiednim zaplanowaniem akcji spowoduje odinstalowanie, którego szukasz. Pamiętaj, aby podać kody aktualizacji wszystkich produktów, które chcesz usunąć.

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

Pamiętaj, że jeśli jesteś ostrożny ze swoimi kompilacjami, możesz zapobiec przypadkowemu zainstalowaniu starszej wersji Twojego produktu na nowszej. Do tego służy pole Maximum. Kiedy budujemy instalatory, ustawiamy UpgradeVersion Maximum do tworzonej wersji, ale IncludeMaximum = „no”, aby zapobiec temu scenariuszowi.

Masz do wyboru harmonogram planowania RemoveExistingProducts. Wolę zaplanować to po InstallFinalize (niż po InstallInitialize, jak zalecili inni):

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

Pozostawia to poprzednią wersję produktu zainstalowaną do momentu skopiowania nowych plików i kluczy rejestru. To pozwala mi migrować dane ze starej wersji do nowej (na przykład zmieniłeś przechowywanie preferencji użytkownika z rejestru na plik XML, ale chcesz być uprzejmy i migrować ich ustawienia). Ta migracja jest wykonywana w odroczonej akcji niestandardowej tuż przed InstallFinalize.

Kolejną korzyścią jest wydajność: jeśli istnieją niezmienione pliki, Instalator Windows nie zawraca sobie głowy kopiowaniem ich ponownie, gdy planujesz po InstallFinalize. Jeśli planujesz po InstallInitialize, poprzednia wersja jest najpierw całkowicie usuwana, a następnie instalowana jest nowa wersja. Powoduje to niepotrzebne usuwanie i ponowne kopiowanie plików.

Aby zapoznać się z innymi opcjami planowania, zobacz temat pomocy RemoveExistingProducts w MSDN. W tym tygodniu link to: http://msdn.microsoft.com/en-us/library/aa371197.aspx

Brian Gillespie
źródło
2
@Brian Gillespie: co oznacza „... jeśli istnieją niezmienione pliki ...”? Jakie są kryteria decydujące o tym, kiedy Instalator Windows zdecyduje, kiedy zastąpić plik, AssemblyVersion, AssemblyFileVersion, rozmiar pliku, ...?
donttellya
2
@donttellya +1 nauczył się tego na własnej skórze. RemoveExistingProductszostało zaplanowane na później, InstallFinalizea biblioteki DLL nie były aktualizowane, ponieważ assemblyVersion nie uległo zmianie, ale inne pola, takie jak AssemblyProduct, były. Nie chcę być na łasce procedury porównywania plików - chcę tylko poprzedniej aplikacji GONE
wal
16

Być może lepiej zapytać o to na liście mailingowej użytkowników WiX .

Z WiX najlepiej jest korzystać przy dokładnym zrozumieniu działania Instalatora Windows. Możesz rozważyć uzyskanie „ Przewodnika po Instalatorze Windows ”.

Działanie, które usuwa istniejący produkt, jest działaniem RemoveExistingProducts . Ponieważ konsekwencje tego, co robi, zależą od tego, gdzie jest zaplanowane - mianowicie, czy awaria powoduje ponowną instalację starego produktu i czy niezmienione pliki są ponownie kopiowane - musisz sam to zaplanować.

RemoveExistingProductsprzetwarza <Upgrade>elementy w bieżącej instalacji, dopasowując @Idatrybut doUpgradeCode (określonego w <Product>elemencie) wszystkich zainstalowanych produktów w systemie. UpgradeCodeDefiniuje rodzinę produktów pokrewnych. Wszelkie produkty, które mają ten kod aktualizacji, których wersje mieszczą się w określonym zakresie i w których UpgradeVersion/@OnlyDetectatrybut jest no(lub jest pominięty), zostaną usunięte.

Dokumentacja dla RemoveExistingProducts wspomina o ustawianiu UPGRADINGPRODUCTCODEwłaściwości. Oznacza to, że proces odinstalowywania usuwanego produktu otrzymuje tę właściwość, której wartością jest Product/@Idprodukt, który jest instalowany.

Jeśli oryginalna instalacja nie zawierała UpgradeCode, nie będzie można korzystać z tej funkcji.

Mike Dimmick
źródło
21
Bez wątpienia Mike doskonale wie, o czym mówi, z całym szacunkiem, ale wzdycham z rozpaczą, że zastanawiam się nad bałaganem w moim umyśle, który dobrze rozumie, co robi Instalator Windows. Zanim się zorientuję, będę wykonywał zadania konsultingowe w zakresie Java i .NET dla klientów Enterprise w dużych miastach centrum technologicznego, poza obwodnicą, wypełniając moje raporty TPS i zastanawiając się, dlaczego życie wydaje się takie puste. Myślę, że mój następny projekt mógłby zostać zainstalowany z NSIS, który pomimo wszystkich swoich wad, jak niedorzeczny język podobny do asemblera, nie pozwolił mi zrozumieć, co robi Instalator Windows.
Jonathan Hartley
2
@Tartley - skorzystaj z InnoSetup, który pozwoli Ci zaoszczędzić język asemblera :) Upewnij się, że złapałeś także IStool, to bardzo pomaga. Ponadto - zgodził się, że w przypadku prostych instalacji wszystko to jest zbyt skomplikowane, ale myślę, że naprawdę potrzebują tej złożoności do zainstalowania czegoś takiego jak SQL Server 2008 ...
Roman Starkov,
11

Skorzystałem z tej witryny, aby pomóc mi zrozumieć podstawy aktualizacji WiX:

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

Następnie utworzyłem przykładowy instalator (zainstalowałem plik testowy), a następnie utworzyłem instalatora uaktualnienia (zainstalowałem 2 przykładowe pliki testowe). To da ci podstawowe zrozumienie działania mechanizmu.

I jak powiedział Mike w książce Apress „The Definitive Guide to Windows Installer”, pomoże ci to zrozumieć, ale nie jest napisane przy użyciu WiX.

Inną stroną, która była bardzo pomocna, była ta:

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

CheGueVerra
źródło
Przykład na stronie nie działa zgodnie z oczekiwaniami wix.tramontana.co.hu/tutorial/upgrades-and-modularization/… . Bawiłem się tym. Możliwe jest nawet obniżenie wersji, gdy strona stwierdzi, że będzie to zabronione
sergtk,
10

Przeczytałem dokumentację WiX , pobrałem przykłady, ale wciąż miałem wiele problemów z aktualizacjami. Niewielkie uaktualnienia nie powodują odinstalowania poprzednich produktów, pomimo możliwości ich określenia. Spędziłem ponad jeden dzień na badaniach i odkryłem, że WiX 3.5 wprowadził nowy tag do aktualizacji. Oto użycie:

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

Ale główną przyczyną problemów było to, że dokumentacja mówi o używaniu parametrów „ REINSTALL = ALL REINSTALLMODE = vomus ” w przypadku drobnych i małych aktualizacji, ale nie oznacza to, że parametry te są ZABRONIONE w przypadku dużych aktualizacji - po prostu przestają działać. Dlatego nie powinieneś używać ich z ważnymi aktualizacjami.

Sasha
źródło
7

Proponuję rzucić okiem na samouczek Alexa Szewczuka. Wyjaśnia „poważną aktualizację” poprzez WiX z dobrym praktycznym przykładem z MSI na WiX, część 8 - Ważna aktualizacja .

Faraz
źródło
Dzięki za link do tego artykułu ... to fantastyczne!
Robert P,
7

Jedną ważną rzeczą, za którą tęskniłem na chwilę od samouczków (skradziony z http://www.tramontana.co.hu/wix/lesson4.php ), co spowodowało błędy „Inna wersja tego produktu jest już zainstalowana”:

* Małe aktualizacje oznaczają niewielkie zmiany w jednym lub kilku plikach, w przypadku których zmiana nie gwarantuje zmiany wersji produktu (major.minor.build). Nie musisz również zmieniać identyfikatora GUID produktu. Pamiętaj, że zawsze musisz zmienić GUID pakietu podczas tworzenia nowego pliku .msi, który pod każdym względem różni się od poprzednich. Instalator śledzi zainstalowane programy i znajduje je, gdy użytkownik chce zmienić lub usunąć instalację za pomocą tych identyfikatorów GUID. Użycie tego samego identyfikatora GUID dla różnych pakietów wprowadzi instalatora w błąd.

Niewielkie aktualizacje oznaczają zmiany, w przypadku których wersja produktu już się zmieni. Zmodyfikuj atrybut Version znacznika Product. Produkt pozostanie taki sam, więc nie trzeba zmieniać identyfikatora GUID produktu, ale oczywiście uzyskać nowy identyfikator GUID pakietu.

Główne aktualizacje oznaczają znaczące zmiany, takie jak przejście z jednej pełnej wersji do drugiej. Zmień wszystko: atrybut wersji, identyfikatory GUID produktów i pakietów.

Daniel Morritt
źródło
3
Pakiet: Typ identyfikatora: AutogenGuid opis: Identyfikator GUID kodu pakietu dla produktu lub modułu scalania. Podczas kompilowania produktu nie należy ustawiać tego atrybutu, aby umożliwić wygenerowanie kodu pakietu dla każdej kompilacji. Podczas kompilowania modułu scalającego ten atrybut musi być ustawiony na identyfikator modularyzacji. ---- więc nie musimy zwracać uwagi na identyfikator paczki, prawda?
Cooper.Wu
Twój link nie działa
bam500
5

Korzystam z najnowszej wersji WiX (3.0) i nie mogłem uruchomić powyższej wersji. Ale to zadziałało:

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

Pamiętaj, że PUT-GUID-HERE powinien być taki sam jak GUID, który zdefiniowałeś we właściwości UpgradeCode produktu.

Merill Fernando
źródło
2

Poniżej działało dla mnie.

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

Upewnij się, że kod aktualizacji w produkcie jest zgodny z identyfikatorem w aktualizacji.

NishantJ
źródło
1

To właśnie działało dla mnie, nawet przy dużej klasie DOWN :

<Wix ...>
  <Product ...>
    <Property Id="REINSTALLMODE" Value="amus" />
    <MajorUpgrade AllowDowngrades="yes" />
Gian Marco Gherardi
źródło