Установщик Windows удаляет файл с версией во время обновления продукта, вместо того, чтобы понижать его

Мы используем wix для создания наших настроек. Для обновления мы используем основные обновления, как показано в этом ответе Роба Меншинга. (В более новых версиях wix вы можете использовать элемент MajorUpgrade.) Это обычно работает хорошо. Старый продукт удаляется, затем новый продукт устанавливается.

Тем не менее, очевидно, что вышеупомянутое не полностью эквивалентно удалению старого продукта вручную и последующей установке нового продукта вручную.

Рассмотрим, например, следующий сценарий:

  • выпущена версия 1.0 нашего продукта, содержащая версию dll третьей стороны
  • выпущена версия 1.1 нашего продукта, содержащая версию 5.1 той же третьей стороны dll
  • Выпущена версия 1.2 нашего продукта, снова пониженная до версии 5.0 третьей стороны dll, потому что мы обнаружили, что новая версия создала больше проблем, чем решала.

Очевидно, что с логикой обновления wix, связанной выше, 3 -ий DLL библиотеки исчезнет при обновлении с версии 1.1 до 1.2. Ремонт необходим для его восстановления.

Есть ли другой способ обновления, который будет работать для этого сценария? Я думаю, что я ищу, это логика обновления, которая позволяет понизить класс компонентов, ведя себя точно так, как будто один вручную удаляет старый продукт, а затем вручную устанавливает новый продукт.

Ответ 1

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

Чтобы устранить эту проблему, мы перемещали действие RemoveExistingProducts над действием CostFinalize.

Я знаю, что документация на MSDN рекомендует размещать RemoveExistingProducts после InstallValidate, и я не уверен, что если поставить его перед действием InstallValidate любые негативные побочные эффекты для незначительных обновлений, но мы решили только выполнить основные обновления для наших продуктов, чтобы это решение, похоже, сработало для нас.

Ответ 2

Поведение, подобное этому, обычно связано с секвенированием RemoveExistingProducts. Если это происходит достаточно поздно, установщик Windows выяснит, что на машине установлена ​​более новая версия .dll, поэтому для версии 1.2 ее не нужно устанавливать. Однако, когда RemoveExistingProducts приводит к удалению .dll, ничего не возвращает.

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

Ответ 3

Попробуйте запланировать RemoveExistingProducts раньше, сразу после InstallValidate, и измените значение свойства REINSTALLMODE на amus. Таким образом, старый продукт будет полностью удален перед любыми файлами из нового продукта копируется и режим заставит заново установить файлы. a

Ответ 4

Это неоптимально, но я исправил ту же проблему, переименовав DLL третьей стороны и изменив GUID на связанном с ним компоненте node в файле .wxs.

Ответ 5

Спустя годы эта тема помогла мне в правильном направлении. Пример полноты с перемещением RemoveExisitingProducts до калькуляции:

<Upgrade Id="UPGRADE-GUID-HERE">
    <UpgradeVersion OnlyDetect="no" Property="UPGRADABLEFOUND"
        Maximum="$(var.ProductVersion)" IncludeMaximum="yes" />
    <UpgradeVersion OnlyDetect="yes" Property="NEWERFOUND"
        Minimum="$(var.ProductVersion)" IncludeMinimum="no" />
</Upgrade>

<InstallExecuteSequence>
    <Custom Action="NoDowngrade" After="FindRelatedProducts">NEWERFOUND</Custom>
    <RemoveExistingProducts Before="CostInitialize" />
</InstallExecuteSequence>

<CustomAction Id="NoDowngrade" Error="A newer version of $(var.ProductName) is already installed." />

Ответ 6

Вот мое окончательное решение, основанное на ответе @Spacemani.

Он создает записи таблицы MSI (Upgrade, LaunchCondition и т.д.), Аналогичные этой

<MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeErrorMessage)" />

но дает вам полный контроль над InstallExecuteSequence.

<!-- Product upgrade -->
<Upgrade Id="$(var.UpgradeCode)">
  <UpgradeVersion OnlyDetect="no" Property="WIX_UPGRADE_DETECTED"
                  Maximum="$(var.ProductVersion)" IncludeMaximum="no" IncludeMinimum="no"
                  MigrateFeatures="yes" />
  <UpgradeVersion OnlyDetect="yes" Property="WIX_DOWNGRADE_DETECTED"
                  Minimum="$(var.ProductVersion)" IncludeMinimum="no" />
</Upgrade>
<InstallExecuteSequence>
  <RemoveExistingProducts Before="CostInitialize" />
</InstallExecuteSequence>
<Condition Message="!(loc.DowngradeErrorMessage)">NOT WIX_DOWNGRADE_DETECTED</Condition>

Обратите внимание, что вам нужно подавить ошибки ICE27 в вашем файле .wixproj следующим образом.

<PropertyGroup>
  <SuppressIces>ICE27</SuppressIces>
</PropertyGroup>