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

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

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

12 ответов

Решение

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

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

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

Наконец я нашел решение - я публикую его здесь для других людей, которые могут иметь такую ​​же проблему (все 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

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

<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 должен быть идентичен.

Элемент 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

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

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

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

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

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

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

Я прочитал документацию по 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" для небольших и небольших обновлений, но при этом не говорится, что эти параметры ЗАПРЕЩЕНЫ для крупных обновлений - они просто перестают работать. Таким образом, вы не должны использовать их с серьезными обновлениями.

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

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

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

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

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

http://web.archive.org/web/20110209022712/http://wixwiki.com/index.php?title=Main_Page

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

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

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

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

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

Я использую последнюю версию 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 Продукта.

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

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

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

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

<Wix ...>
  <Product ...>
    <Property Id="REINSTALLMODE" Value="amus" />
    <MajorUpgrade AllowDowngrades="yes" />
Другие вопросы по тегам