Как добавить пользовательское действие WiX, которое происходит только при удалении (через MSI)?

Я хотел бы изменить установщик MSI (созданный через WiX), чтобы удалить весь каталог при удалении.

Я понимаю RemoveFile а также RemoveFolder параметры в WiX, но они недостаточно надежны для рекурсивного удаления всей папки, содержимое которой было создано после установки.

Я заметил похожий вопрос переполнения стека Удаление файлов при удалении WiX, но мне было интересно, можно ли это сделать проще, используя вызов пакетного сценария для удаления папки.

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

7 ответов

РЕДАКТИРОВАТЬ: Возможно, посмотрите на ответ сразу ниже.


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

альтернативный текст

Поэтому в моем случае я хотел, чтобы ЦС работал только при деинсталляции, а не при обновлении, не исправлении или модификации. Согласно таблице выше я должен был использовать

<Custom Action='CA_ID' Before='other_CA_ID'>
        (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>

И это сработало!

Есть много проблем с ответом yaluna, также имена свойств чувствительны к регистру, Installed это правильное написание (INSTALLED не будет работать). Таблица выше должна была быть такой:

Также при условии полного восстановления и удаления фактические значения свойств могут быть:

Документация по синтаксису выражений WiX гласит:

В этих выражениях вы можете использовать имена свойств (помните, что они чувствительны к регистру).

Свойства задокументированы в Руководстве по установке Windows (например, Установлено)

РЕДАКТИРОВАТЬ: небольшая коррекция к первой таблице; очевидно, "удаление" может произойти только с REMOVE являющийся True,

Вы можете сделать это с помощью специального действия. Вы можете добавить ссылку на свое пользовательское действие в разделе <InstallExecuteSequence>:

<InstallExecuteSequence>
...
  <Custom Action="FileCleaner" After='InstallFinalize'>
          Installed AND NOT UPGRADINGPRODUCTCODE</Custom>

Тогда вам также придется определить свое действие в <Product>:

<Product> 
...
  <CustomAction Id='FileCleaner' BinaryKey='FileCleanerEXE' 
                ExeCommand='' Return='asyncNoWait'  />

Где FileCleanerEXE - это двоичный файл (в моем случае это небольшая программа на С ++, выполняющая пользовательское действие), которая также определяется в <Product>:

<Product> 
...
  <Binary Id="FileCleanerEXE" SourceFile="path\to\fileCleaner.exe" />

Настоящий трюк с этим Installed AND NOT UPGRADINGPRODUCTCODE условие для настраиваемого действия, при котором ваше действие будет запускаться при каждом обновлении (поскольку обновление действительно является деинсталляцией, а затем переустановите). Что, если вы удаляете файлы, вероятно, не хотите, чтобы вы хотели во время обновления.

С другой стороны: я рекомендую пройти через проблему, используя что-то вроде программы на C++ для выполнения действия вместо пакетного скрипта из-за его мощности и контроля - и вы можете предотвратить мигание окна "cmd prompt", пока Ваш установщик работает.

Самая большая проблема с пакетным сценарием - обработка отката, когда пользователь нажимает кнопку отмены (или что-то идет не так во время вашей установки). Правильный способ обработки этого сценария - создать CustomAction, который добавляет временные строки в таблицу RemoveFiles. Таким образом установщик Windows обрабатывает случаи отката для вас. Это безумно проще, когда вы видите решение.

В любом случае, чтобы действие выполнялось только во время удаления, добавьте элемент Condition с помощью:

REMOVE ~= "ALL"

~= говорит, что сравнивать без учета регистра (хотя я думаю, что ALL всегда uppercaesd). См. Документацию MSI SDK о синтаксисе условий для получения дополнительной информации.

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

Вот набор свойств, которые я сделал, которые более интуитивно понятны, чем встроенные. Условия основаны на таблице истинности, представленной выше ahmd0.

<!-- truth table for installer varables (install vs uninstall vs repair vs upgrade) https://stackru.com/a/17608049/1721136 -->
 <SetProperty Id="_INSTALL"   After="FindRelatedProducts" Value="1"><![CDATA[Installed="" AND PREVIOUSVERSIONSINSTALLED=""]]></SetProperty>
 <SetProperty Id="_UNINSTALL" After="FindRelatedProducts" Value="1"><![CDATA[PREVIOUSVERSIONSINSTALLED="" AND REMOVE="ALL"]]></SetProperty>
 <SetProperty Id="_CHANGE"    After="FindRelatedProducts" Value="1"><![CDATA[Installed<>"" AND REINSTALL="" AND PREVIOUSVERSIONSINSTALLED<>"" AND REMOVE=""]]></SetProperty>
 <SetProperty Id="_REPAIR"    After="FindRelatedProducts" Value="1"><![CDATA[REINSTALL<>""]]></SetProperty>
 <SetProperty Id="_UPGRADE"   After="FindRelatedProducts" Value="1"><![CDATA[PREVIOUSVERSIONSINSTALLED<>"" ]]></SetProperty>

Вот пример использования:

  <Custom Action="CaptureExistingLocalSettingsValues" After="InstallInitialize">NOT _UNINSTALL</Custom>
  <Custom Action="GetConfigXmlToPersistFromCmdLineArgs" After="InstallInitialize">_INSTALL OR _UPGRADE</Custom>
  <Custom Action="ForgetProperties" Before="InstallFinalize">_UNINSTALL OR _UPGRADE</Custom>
  <Custom Action="SetInstallCustomConfigSettingsArgs" Before="InstallCustomConfigSettings">NOT _UNINSTALL</Custom>
  <Custom Action="InstallCustomConfigSettings" Before="InstallFinalize">NOT _UNINSTALL</Custom>

Вопросы:

  • UPGRADINGPRODUCTCODE устанавливается во время действия RemoveExistingProducts, поэтому любые пользовательские действия, которые вы запускаете ранее, не будут знать, что это обновление https://docs.microsoft.com/en-us/windows/desktop/Msi/upgradingproductcode

Чтобы выполнить действие только при удалении, ни при восстановлении, ни при обновлении, ни при установке, вы можете использовать:

      <Custom Action="ActionName" Before="InstallFinalize"><![CDATA[Installed AND NOT UPGRADINGPRODUCTCODE]]></Custom>

Я использовал Custom Action, отдельно закодированный в C++ DLL, и использовал DLL для вызова соответствующей функции при деинсталляции, используя этот синтаксис:

<CustomAction Id="Uninstall" BinaryKey="Dll_Name" 
              DllEntry="Function_Name" Execute="deferred" />

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

Другие вопросы по тегам