Як додати власну дію WiX, яка відбувається лише під час видалення (через MSI)?


161

Я хотів би змінити інсталятор MSI (створений через WiX ) для видалення цілого каталогу при видаленні.

Я розумію RemoveFileі RemoveFolderпараметри в WiX, але вони недостатньо надійні для рекурсивного видалення цілої папки, яка містить вміст, створений після встановлення.

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

Це перший раз, коли я використовую WiX, і я все ще переживаю спеціальні дії . Що може бути основним прикладом спеціальної дії, яка запустить пакетний сценарій при видаленні?

Відповіді:


188

EDIT : Можливо, подивіться на відповідь, що знаходиться зараз безпосередньо нижче .


Ця тема вже давно болить головою. Нарешті я це зрозумів. В Інтернеті є деякі рішення, але жодне з них насправді не працює. І звичайно, документації немає. Отже, на графіку нижче є кілька властивостей, які пропонується використовувати, та значення, які вони мають для різних сценаріїв установки:

alt текст

Тож у моєму випадку я хотів, щоб ЦС, який працюватиме лише на видаленнях - не оновлення, не ремонту чи модифікації. Відповідно до таблиці, яку я мав використовувати

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

І це спрацювало!


25
Чи правильні значення на цій діаграмі? Навіщо вам потрібно додати REMOVE = "ВСІ"? НЕ UPGRADINGPRODUCTCODE справедливий лише для видалення (згідно діаграми), тому (NOT UPGRADINGPRODUCTCODE) AND (REMOVE = "ALL") також буде істинним лише при видаленні. REMOVE = "ВСІ" видається непотрібним.
Тодд Ропог

2
Я згоден з @ToddRopog - Приклад та таблиця істинності, схоже, не згодні. Це дійсно правильно?
Тім Лонг

19
Таблиця правди трохи неправильна. НЕ ОНОВЛЮВАННЯВИРОБІТЬ ПРОДУКЦІЯ справедлива і для першої інсталяції
Ніл

2
Загальні умови: alekdavis.blogspot.ru/2013/05/…
KindDragon

1
Будь ласка, підтвердьте: "Встановлені та ВСТАНОВЛЕНІ" - це різні речі, лише встановлена ​​установка встановлена ​​Windows Installer. Я не думаю, що INSTALLED працює.
Micha Wiedenmann

140

Існує кілька проблем з відповіддю yaluna , також імена властивостей залежать від регістру, Installedце правильне написання ( INSTALLEDне вийде). Наведена вище таблиця повинна була бути такою:

введіть тут опис зображення

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

введіть тут опис зображення

Документація синтаксису виразів WiX говорить:

У цих виразах можна використовувати імена властивостей (пам’ятайте, що вони відрізняються від регістру).

Властивості задокументовані в Посібнику з інсталятора Windows (наприклад, Встановлено )

EDIT: Невелике виправлення до першої таблиці; очевидно, "Видалити" також може трапитися з простою REMOVEістотою True.


3
Також видається, що REMOVE встановлений для Change
szx

2
Стовпець "Оновлення" - це під час видалення послідовності старої версії або послідовності встановлення нової версії?
Нік Уолі

1
@NickWhaley: Я не розглядав це деякий час, але вважаю, що варіант "Upgrade" є лише при встановленні версії, більшої від встановленої.
ahmd0

1
@ ahmd0, ну звичайно. Але є вкладена установка, яка відбувається в RemoveExistingProducts, яка має зовсім інший набір властивостей. Це те, що знаходиться у вашому стовпці "Оновити". Решта оновлення ідентична стовпцю "Встановити".
Nick Whaley

1
@ NickWhaley: Параметр REMOVE буде істинним для основних оновлень, тобто 1.0.0 до 2.0.0, а не 1.0.0 до 1.1.0 під час виконання попередньої версії деінсталятора попередньої версії. Щоб запустити власну дію під час великого оновлення в нових версіях встановлення, вам потрібно буде посилатися на властивість ActionProperty, визначену в таблиці оновлення MSI для оновлення цієї версії. symantec.com/connect/articles/msi-upgrade-overview msdn.microsoft.com/en-us/library/aa372379%28v=vs.85%29.aspx
Chaoix

48

Це можна зробити за допомогою спеціальної дії. Ви можете додати відгук до власної дії у розділі <InstallExecuteSequence>:

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

Тоді вам також доведеться визначити свою дію під <Product>:

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

Де FileCleanerEXE є двійковою (у моєму випадку трохи програмою c ++, яка виконує власну дію), яка також визначена в <Product> :

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

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

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


3
25 оновлень, але не прийнята відповідь. Ласкаво просимо у світ монтажників! :)
Крістофер Художник

4
Це насправді не працює. Коли ви хочете виконати fileCleaner.exe, який встановлений у вашій власній папці інсталяції, це буде проблемою з куркою-яйцем: CustomActionвиконується "After = 'InstallFinalize'". У цей момент всі файли видаляються з папки "Установка". Також fileCleaner.exe. Таким чином, ви не можете виконати це через CustomAction. Ця відповідь просто неправильна. Мені цікаво 42 звернення!
Саймон

40

Найбільшою проблемою пакетного сценарію є обробка відката, коли користувач натискає скасувати (або під час встановлення щось піде не так). Правильний спосіб впоратися з цим сценарієм - створити CustomAction, який додає тимчасові рядки до таблиці RemoveFiles. Таким чином, інсталятор Windows обробляє справи про відкат для вас. Це шалено простіше, коли ти бачиш рішення.

У будь-якому випадку, щоб виконати дію лише під час видалення, додайте елемент Condition за допомогою:

REMOVE ~= "ALL"

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

PS: Ніколи не було випадку, коли я сів і подумав: "О, пакетний файл був би хорошим рішенням в інсталяційному пакеті". Власне, пошук інсталяційного пакету, в якому є пакетний файл, лише спонукає мене повернути товар за відшкодування.


Я збирався використати пакетний сценарій, а потім побачив розділ PS. Дякуємо, що врятували мене:) Видалення ~ = "ВСЕ" працювало на мене.
ArNumb

12

Ось набір властивостей, які я зробив, які вважають більш інтуїтивними у використанні, ніж вбудовані речі. Умови ґрунтуються на таблиці істинності, поданої вище 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>

Проблеми:


Це чудове рішення. Не забудьте також врахувати умови PATCH та MSIPATCHREMOVE.
Гарет Джакс

У своїй таблиці істинності ви мали на увазі використовувати PREVIOUSVERSIONSINSTALLED замість UPGRADINGPRODUCTCODE, як використовується ahmd0? Я не бачу жодних посилань на PREVIOUSVERSIONSINSTALLED на довідковій сторінці властивостей MSI ( docs.microsoft.com/en-us/windows/win32/msi/property-reference ).
Патрік

Деякі предикати для ваших властивостей не враховують усіх рядків таблиці ahmd0 (встановлено, встановити, перевстановити, оновити програму та знищити). Чи поясніть, будь ласка, чому?
Патрік

0

Я використовував власну дію, кодовану окремо в DLL C ++, і використовував DLL для виклику відповідної функції при видаленні за допомогою цього синтаксису:

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

Використовуючи вищевказаний блок коду, я міг запустити будь-яку функцію, визначену в DLL C ++, при видаленні. FYI, у моїй функції видалення був код щодо очищення поточних даних користувачів та записів реєстру.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.