Мне трудно понять, как правильно устанавливать и удалять пользовательские действия и какова цель отката. У меня есть пользовательское действие под названием CreateFSRegistryLink
это создает REG_LINK
запись реестра (которая не может быть создана MSI / InstallShield непосредственно AFAIK). Я думаю, что по большей части это работает правильно, потому что, если ссылка уже есть, она просто возвращает ERROR_FUNCTION_NOT_CALLED
, который MSI, кажется, обрабатывает изящно, продолжая остальную часть установки. Это гарантирует, что несколько экземпляров продукта могут быть установлены без ошибок (у нас есть несколько экземпляров продукта).
Проблема возникает во время удаления. CreateFSRegistryLink
кажется, снова работает в режиме без отката. Из журнала MSI я вижу, что он работает так, как должен во время устанавливать и но это также работает во время деинсталляция:
Я проверяю режим с помощью:
if (!MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK))
Когда условие выполняется, я записываю сообщение «CreateFSRegistryLink работает в режиме без отката». Когда оно ложно, я записываю сообщение: «CreateFSRegistryLink работает в режиме отката, поэтому был пропущен». Я никогда не видел, чтобы второе сообщение появлялось в журнале.
я имею CreateFSRegistryLink
настроить выполнение In-Script «Отложенное выполнение в контексте системы». У меня также есть другое пользовательское действие DeleteFSRegistryLink
настроить выполнение In-Script «Выполнение отката в системном контексте». Я вижу, что он пропускается во время установки, но не во время деинсталляции (я подозреваю, что он работает нормально во время деинсталляции, но не добавил ведения журнала, чтобы подтвердить это).
У меня также есть пользовательское действие CountOtherFSSystems
это устанавливает FS_SystemCount на количество систем (экземпляров) помимо текущего экземпляра. Я поставил DeleteFSRegisryLink
иметь условие бегать только тогда, когда FS_SystemCount<1
в последовательности Exec. Вот как я могу сказать, что он пропускается во время установки, потому что MSI сообщает, что условие не было выполнено, и так DeleteFSRegistryLink
был пропущен Я ожидаю, что это поможет убедиться, что он работает только тогда, когда последний экземпляр удаляется. Я думаю, что это условие работает на основе вывода журнала, но я не знаю, как это получить DeleteFSRegistryLink
настраиваемое действие для правильной работы во время удаления без CreateFSRegistryLink
действие по переустановке ссылки. Последняя ссылка на DeleteFSRegistryLink
Я вижу в журнале это:
MSI (s) (08:CC) [09:42:23:708]: Executing op: CustomActionSchedule(Action=DeleteFSRegistryLink,ActionType=3329,Source=BinaryData,Target=DeleteFSRegistryLink,)
Я еще не добавил запись в журнал для этой функции, поэтому не знаю, запустилась ли она, но после завершения установки ссылка в реестре все еще там. Это не совсем удивительно, потому что сразу после этого я вижу, что CreateFSRegistryLink
побежал снова:
MSI (s) (08:CC) [09:42:23:708]: Executing op: ActionStart(Name=CreateFSRegistryLink,,)
Action 9:42:23: CreateFSRegistryLink.
MSI (s) (08:CC) [09:42:23:708]: Executing op: CustomActionSchedule(Action=CreateFSRegistryLink,ActionType=3073,Source=BinaryData,Target=CreateFSRegistryLink,)
MSI (s) (08:0C) [09:42:23:739]: Invoking remote custom action. DLL: C:\windows\Installer\MSI37E1.tmp, Entrypoint: CreateFSRegistryLink
MSI (s) (08:70) [09:42:23:739]: Generating random cookie.
MSI (s) (08:70) [09:42:23:739]: Created Custom Action Server with PID 7640 (0x1DD8).
MSI (s) (08:18) [09:42:23:786]: Running as a service.
MSI (s) (08:18) [09:42:23:786]: Hello, I'm your 32bit Elevated custom action server.
CreateFSRegistryLink is running in non-rollback mode.
Я следовал правилу в https://msdn.microsoft.com/en-us/library/aa371369(v=vs.85).aspx «Настраиваемое действие отката должно всегда предшествовать отложенному настраиваемому действию, которое оно откатывает в последовательности действий», что для меня все еще не имеет смысла видеть этот вывод и результаты журнала. Я думаю, что мне здесь не хватает нескольких ключевых моментов.
Это в моем списке «необходимого чтения» для MSI и хорошее место для начала:
Этапы установки и параметры выполнения в сценарии для настраиваемых действий в установщике Windows
Идея состоит в том, что каждое изменение, сделанное MSI, должно быть транзакционным. Вы сможете откатить изменение состояния при сбое во время установки, обновления, восстановления или удаления.
Иногда вы сталкиваетесь с API, где это невозможно. Примером может быть удаление учетной записи пользователя или взаимодействие со старым API метабазы IIS. Если API не поддерживает возможность .commit () .rollback (), вам нужно просто внести изменения в выполнение фазы фиксации. Учитывая, что этап фиксации можно отключить, отключив откат, вы должны сделать это на ранней стадии в этих сценариях.
Прочитайте официальный документ несколько раз, немного переварите его, а затем ответьте на любые другие вопросы, которые у вас остались.
Редактировать: Вот как я настроил свои собственные действия:
FS_SystemCount<1 And $FSRegistry = 3
(Когда компонент FSRegistry устанавливался локально). Вызывает функцию удаления ссылки в реестре.$FSRegistry=3
, Вызывает функцию для создания ссылки в реестре.$FSRegistry<>3
(когда компонент FSRegistry был удален, но откат должен вернуть его обратно). Вызывает функцию для создания ссылки в реестре.FS_SystemCount<1 AND $FSRegistry <> 3
, Вызывает функцию удаления ссылки в реестре.Я проверил следующие случаи:
Пожалуйста, прокомментируйте, если вы видите что-то, что я пропустил здесь. Это кажется довольно полным для меня.
Чтобы добавить мои 2 цента: Кажется, проблема связана с условиями пользовательских действий. Что касается вашего звонка в MsiGetMode, чтобы увидеть, если это откат, зачем? Вы настраиваете пользовательское действие отката перед вашим фактическим отложенным ЦС, и по определению оно будет вызываться только в том случае, если было вызвано исходное пользовательское действие, и оно определено как ЦС отката и не требует никаких условий. Может случиться так, что ваш CA для удаления может быть таким же, как и CA для отката, но, строго говоря, CA для удаления может предположить, что его аналогичный CA для установки работал правильно, если он правильно закодирован и сбой приводит к сбою установки, тогда как для CA отката может потребоваться предположить, что установочный ЦС, возможно, работал только частично и должен проверить состояние системы.
Если при удалении вызывается CreateRegistryFSLink, значит, ваше условие в этом CA неверно.
Если ваш код что-то сделал или не сделал, то вам остается вспомнить, что он сделал, и откат CA отменяет это.
Остальное, похоже, касается условий ваших пользовательских действий. Если вы хотите, чтобы он вызывался только при удалении продукта, используйте REMOVE = «ALL». Если у вас есть CA, связанные конкретно с компонентом или удалением компонента, то (как говорит Крис) используйте компонент или условие компонента, они здесь:
https://msdn.microsoft.com/en-us/library/aa368012(v=vs.85).aspx
Если вы хотите, чтобы удаленный ЦС запускался до тех пор, пока продукт не обновляется, тогда будут работать REMOVE = «ALL» и NOT UPGRADINGPRODUCTCODE.
Поэтому, если вы все еще застряли, это может помочь опубликовать ваши определения CA, в частности, условия и типы.