Как добавить пользовательское действие WiX, которое происходит только при удалении (через MSI)? - PullRequest
148 голосов
/ 26 ноября 2008

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

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

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

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

Ответы [ 6 ]

181 голосов
/ 09 апреля 2009

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


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

alt text

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

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

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

120 голосов
/ 12 июля 2013

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

enter image description here

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

enter image description here

Документация Синтаксис WiX гласит:

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

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

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

47 голосов
/ 26 ноября 2008

Вы можете сделать это с помощью специального действия. Вы можете добавить ссылку на свое настраиваемое действие в <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 в Custom Action, при котором ваше действие будет запускаться при каждом обновлении (поскольку обновление действительно является деинсталлируемым, переустановите его). Который, если вы удаляете файлы, вероятно, не нужен во время обновления.

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

39 голосов
/ 26 ноября 2008

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

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

REMOVE ~= "ALL"

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

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

4 голосов
/ 06 июля 2018

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

<!-- truth table for installer varables (install vs uninstall vs repair vs upgrade) https://stackoverflow.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
0 голосов
/ 25 апреля 2014

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

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

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

...