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

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

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

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

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

Ответ 1

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

alt text

Итак, в моем случае мне нужен CA, который будет работать только на uninstalls - не обновления, а не ремонт или модификация. Согласно приведенной выше таблице мне пришлось использовать

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

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

Ответ 2

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

enter image description here

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

enter image description here

В документации Симуляция синтаксиса WiX говорится:

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

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

EDIT: небольшая поправка к первой таблице; очевидно, что "Uninstall" также может произойти, если только REMOVE является True.

Ответ 3

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

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

Ответ 4

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

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

REMOVE ~= "ALL"

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

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

Ответ 5

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

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

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