Как реализовать обновление установщика WiX?

233

На работе мы используем WiX для сборки инсталляционных пакетов. Мы хотим, чтобы установка продукта X привела к удалению предыдущей версии этого продукта на этом компьютере.

Я читал в нескольких местах в Интернете о серьезном обновлении, но не смог заставить его работать. Кто-нибудь может указать, какие именно шаги мне нужно предпринять, чтобы добавить функцию удаления предыдущей версии в WiX?

Dror Helper
источник

Ответы:

189

В новейших версиях (начиная с бета-версии 3.5.1315.0) вы можете использовать элемент MajorUpgrade вместо использования своей собственной.

Например, мы используем этот код для автоматического обновления. Это предотвращает понижения, выдает локализованное сообщение об ошибке, а также предотвращает обновление уже существующей идентичной версии (то есть обновляются только более низкие версии):

<MajorUpgrade
    AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
    AllowSameVersionUpgrades="no"
    />
Муравей
источник
8
В блоге Боба Арнсона об этом содержится много приятной информации.
Дейв Андерсен
17
Примечание: нигде не документировано, но <MajorUpgrade>элемент " " должен быть помещен после <Package> . В противном случае candleвыдает следующую ошибку: «ошибка CNDL0107: сбой проверки схемы со следующей ошибкой в ​​строке 1, столбец 473: элемент« Продукт »в пространстве имен» schemas.microsoft.com/wix/2006/wi «имеет недопустимый дочерний элемент» MajorUpgrade 'in namespace' schemas.microsoft.com/wix/2006/wi '. Список возможных ожидаемых элементов:' Package '. ".
Роб У
21
+1 Этот ответ должен получить как можно больше голосов; очень заманчиво пойти с ответом, который имеет 5-кратное количество голосов, но использует более старые подходы.
Линн рушится
1
Хорошая точка зрения. Я добавил пример, чтобы люди не игнорировали его только потому, что его нет!
Муравей
6
Просто хочу указать, что вам не нужно указывать AllowDowngradesили AllowSameVersionUpgrades. По умолчанию они уже нет.
Световой
221

Наконец я нашел решение - я публикую его здесь для других людей, которые могут иметь такую ​​же проблему (все 5 из вас):

  • Измените идентификатор продукта на *
  • Под продуктом добавьте следующее:

    <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> 
    
  • Под InstallExecuteSequence добавить:

    <RemoveExistingProducts Before="InstallInitialize" /> 

Отныне всякий раз, когда я устанавливаю продукт, он удаляет предыдущие установленные версии.

Примечание: замените идентификатор обновления на свой собственный GUID

Dror Helper
источник
153
да, изучение WiX - это все равно что пытаться выяснить неясные заклинания, которые кто-то решил «иметь смысл» для выполнения простого действия. Вроде как UNIX.
MMR
6
Кроме того, что именно делает «Изменить идентификатор продукта на *»? Создает ли каждый раз новый идентификатор продукта? Есть ли последствия для вашего продукта, не имеющего фиксированный идентификатор больше? - это звучит как излишнее.
Энтони
10
@Antony, @Dror Helper: Я уверен, что вам не следует использовать «*» для генерации нового GUID здесь. GUID внутри (Upgrade Id = "") должен быть жестко запрограммирован и фиксирован, и он должен совпадать с GUID в вашем атрибуте (Product UpgradeCode = "").
Джонатан Хартли
37
Я думаю, что вы, вероятно, должны отредактировать свой пример там, чтобы НЕ иметь фактический GUID. Я уверен, что люди будут копировать и вставлять это и использовать его дословно. Может быть, использовать "YOUR-PRODUCT'S-UPGRADECODE-GUID-HERE"?
Браун
12
В вашем примере есть ошибка. MSI ProductVersionподдерживает только три поля версий; поэтому четвертое поле не будет сравниваться вообще. См. Примечание под VersionMin и VersionMax в msdn.microsoft.com/en-us/library/aa372379(VS.85).aspx
Шридхар Ратнакумар
89

Ниже приводится синтаксис, который я использую для крупных обновлений:

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

Как отметил @Brian Gillespie, существуют другие места для планирования RemoveExistingProducts в зависимости от желаемой оптимизации. Обратите внимание, что PUT-GUID-HERE должен быть идентичен.

Роб Меншинг
источник
2
Я читаю раздел «Обновление и исправления» в книге Ника Рамиреса о Wix здесь, и он заявляет, что если вы запланируете RemoveExistingProducts после InstallInitialize, то вы ДОЛЖНЫ также запланировать <InstallExecute After="RemoveExistingProducts" />. В вашем примере этого нет - значит ли это, что книга не права?
Вим Коенен
3
Я никогда не планирую явно InstallExecute.
Роб Меншинг
1
Я не. В WiX v3.6 Burn позволяет легко выполнять незначительные обновления, но без Burn требуется ручное взаимодействие с пользователем (необходимо указать параметры командной строки), что делает незначительные обновления в основном бесполезными. :)
Роб Мэншинг
1
@RobMensching: как избежать установки более старой версии поверх более новой? Ваш ответ работает для меня (единственный пример «крупного обновления», который я могу собрать для компиляции с WiX v3.5.2519.0), но возможно установить более старую версию (после этого я вижу обе версии в «Добавить / Удалить программы ").
Кристиан Шпехт
4
Хорошо, я только что нашел элемент MajorUpgrade в этом ответе, который делает именно то, что я хочу, включая предотвращение понижений.
Кристиан Шпехт
40

Элемент Upgrade внутри элемента Product в сочетании с правильным планированием действия выполнит удаление, которое вы после. Не забудьте перечислить коды обновления всех продуктов, которые вы хотите удалить.

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

Обратите внимание, что, если вы будете осторожны с вашими сборками, вы можете предотвратить случайную установку более старой версии вашего продукта поверх более новой. Вот для чего используется поле Maximum. Когда мы собираем установщики, мы устанавливаем UpgradeVersion Maximum для создаваемой версии, но IncludeMaximum = "no", чтобы предотвратить этот сценарий.

У вас есть выбор относительно планирования RemoveExistingProducts. Я предпочитаю планировать его после InstallFinalize (а не после InstallInitialize, как рекомендовали другие):

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

При этом предыдущая версия продукта остается установленной до тех пор, пока не будут скопированы новые файлы и разделы реестра. Это позволяет мне переносить данные из старой версии в новую (например, вы переключили хранилище пользовательских настроек из реестра в файл XML, но вы хотите быть вежливым и перенести их настройки). Эта миграция выполняется в отложенном настраиваемом действии непосредственно перед InstallFinalize.

Еще одним преимуществом является эффективность: если есть неизмененные файлы, установщик Windows не потрудится копировать их снова, когда вы планируете после InstallFinalize. Если вы планируете после InstallInitialize, предыдущая версия сначала полностью удаляется, а затем устанавливается новая версия. Это приводит к ненужному удалению и повторному копированию файлов.

Другие параметры планирования см. В разделе справки RemoveExistingProducts в MSDN. На этой неделе ссылка: http://msdn.microsoft.com/en-us/library/aa371197.aspx

Брайан Гиллеспи
источник
2
@ Брайан Гиллеспи: что значит "... если есть неизмененные файлы ..."? По каким критериям установщик Windows должен решить, когда заменить файл, AssemblyVersion, AssemblyFileVersion, размер файла, ...?
Донттеля
2
@donttellya +1 научился этому нелегко. RemoveExistingProductsбыло запланировано после InstallFinalizeи dll не обновлялись, так как AssemblyVersion не изменилась, но другие поля, такие как AssemblyProduct, были. Я не хочу быть во власти рутины сравнения файлов - я просто хочу , предыдущее приложение GONE
валь
16

Возможно, вам лучше спросить об этом в списке рассылки WiX-пользователей .

WiX лучше всего использовать с четким пониманием того, что делает установщик Windows. Вы можете получить « Полное руководство по установке Windows ».

Действие, которое удаляет существующий продукт, является действием RemoveExistingProducts . Поскольку последствия того, что он делает, зависят от того, где он запланирован, а именно от того, приведет ли сбой к переустановке старого продукта и повторному копированию неизмененных файлов, вы должны запланировать его самостоятельно.

RemoveExistingProductsобрабатывает <Upgrade>элементы в текущей установке, сопоставляя @Idатрибут с UpgradeCode(указанным в <Product>элементе) всех установленных продуктов в системе. UpgradeCodeОпределяет семейство связанных продуктов. Любые продукты, имеющие этот код UpgradeCode, версии которого попадают в указанный диапазон и где UpgradeVersion/@OnlyDetectатрибут no(или отсутствует), будут удалены.

В документации RemoveExistingProductsупоминается установка UPGRADINGPRODUCTCODEсвойства. Это означает, что процесс удаления удаляемого продукта получает это свойство, значение которого соответствует Product/@Idустанавливаемому продукту.

Если ваша первоначальная установка не включала в себя UpgradeCode, вы не сможете использовать эту функцию.

Майк Диммик
источник
21
Без сомнения, Майк точно знает, о чем говорит, при всем моем уважении, но я с отчаянием вздыхаю, размышляя над тем, чтобы загромождать мой разум твердым пониманием того, что делает установщик Windows. Прежде чем я это узнаю, я буду выполнять консалтинговые работы по Java и .NET для корпоративных клиентов в огромных городах технических центров, за пределами кольцевой дороги, заполняя свои отчеты TPS и удивляясь, почему жизнь кажется такой пустой. Я думаю, что мой следующий проект может быть установлен с NSIS, который при всех его ошибках, как нелепый язык, похожий на ассемблер, не дал мне понять, что делает установщик Windows.
Джонатан Хартли
2
@Tartley - иди с InnoSetup, это спасет тебя от языка, похожего на ассемблер :) Убедитесь, что ты тоже взял IStool, это очень помогает. Кроме того - согласился, что для простых установок все это слишком сложно, но я думаю, что им действительно нужна эта сложность для установки чего-то вроде SQL Server 2008 ...
Роман Старков
11

Я использовал этот сайт, чтобы помочь мне понять основы обновления WiX:

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

После этого я создал образец установщика (установил тестовый файл), затем создал установщик обновления (установил 2 образца проверочных файлов). Это даст вам общее представление о том, как работает механизм.

И, как сказал Майк в книге от Apress «Полное руководство по установщику Windows», он поможет вам разобраться, но он написан не с использованием WiX.

Еще один сайт, который был очень полезен, был этот:

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

CheGueVerra
источник
Пример на странице не работает должным образом . Wix.tramontana.co.hu/tutorial/upgrades-and-modularization/… . Я играл с этим. Можно даже понизить рейтинг, когда на странице указано, что это будет запрещено
sergtk
10

Я прочитал документацию по WiX , скачал примеры, но у меня все еще было много проблем с обновлениями. Незначительные обновления не выполняют удаление предыдущих продуктов, несмотря на возможность указать их удаление. Я потратил больше одного дня на расследования и обнаружил, что WiX 3.5 ввел новый тег для обновлений. Вот использование:

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

Но основная причина проблем заключалась в том, что в документации сказано использовать параметры « REINSTALL = ALL REINSTALLMODE = vomus » для небольших и малых обновлений, но при этом не говорится, что эти параметры ЗАПРЕЩЕНЫ для крупных обновлений - они просто перестают работать. Таким образом, вы не должны использовать их с серьезными обновлениями.

Саша
источник
7

Я бы посоветовал взглянуть на учебник Алекса Шевчука. Он объясняет «серьезное обновление» через WiX с помощью хорошего практического примера: « От MSI до WiX, часть 8 - Основное обновление» .

Фараз
источник
Спасибо за ссылку на эту статью ... это фантастика!
Роберт П
7

Одна важная вещь, которую я пропустил из учебников некоторое время (украденная у http://www.tramontana.co.hu/wix/lesson4.php ), которая привела к ошибкам «Другая версия этого продукта уже установлена»:

* Небольшие обновления означают небольшие изменения в одном или нескольких файлах, где изменение не гарантирует изменения версии продукта (major.minor.build). Вам также не нужно менять GUID продукта. Обратите внимание, что вы всегда должны изменять GUID пакета при создании нового MSI-файла, который отличается от предыдущих в любом отношении. Установщик отслеживает ваши установленные программы и находит их, когда пользователь хочет изменить или удалить установку, используя эти GUID. Использование одного и того же GUID для разных пакетов может привести к путанице в установщике.

Незначительные обновления означают изменения, когда версия продукта уже изменится. Измените атрибут Version тега Product. Продукт останется прежним, поэтому вам не нужно менять GUID продукта, но, конечно, получить новый GUID пакета.

Основные обновления означают значительные изменения, такие как переход с одной полной версии на другую. Измените все: атрибут версии, идентификатор продукта и пакета.

Даниэль Морритт
источник
3
Package: Id type: AutogenGuid Описание: GUID кода пакета для продукта или модуля слияния. При компиляции продукта этот атрибут не следует устанавливать для того, чтобы позволить генерировать код пакета для каждой сборки. При компиляции модуля слияния этот атрибут должен быть установлен в гид модуляции. ---- так что нам не нужно обращать внимание на идентификатор пакета, верно?
Cooper.Wu 18.10.11
Ваша ссылка мертва
bam500
5

Я использую последнюю версию WiX (3.0) и не могу заставить работать выше. Но это сработало:

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

Обратите внимание, что PUT-GUID-HERE должен совпадать с GUID, который вы определили в свойстве UpgradeCode Продукта.

Мерилл Фернандо
источник
2

Ниже работал для меня.

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

Убедитесь, что код обновления в продукте соответствует идентификатору в обновлении.

NishantJ
источник
1

Это то, что сработало для меня, даже с основным классом ВНИЗ :

<Wix ...>
  <Product ...>
    <Property Id="REINSTALLMODE" Value="amus" />
    <MajorUpgrade AllowDowngrades="yes" />
Джан Марко Герарди
источник