C++ 卸载与回滚期间的MSI自定义操作

C++ 卸载与回滚期间的MSI自定义操作,c++,windows-installer,installshield,C++,Windows Installer,Installshield,我很难理解如何正确安装和卸载自定义操作,以及回滚的目的是什么。我有一个名为CreateFSRegistryLink的自定义操作,它创建一个REG\u链接注册表项(MSI/InstallShield不能直接在AIK中创建)。我认为这在很大程度上是正常运行的,因为如果链接已经存在,它只会返回ERROR\u FUNCTION\u NOT\u CALLED,MSI似乎能很好地处理它,继续安装的其余部分。这确保了产品的多个实例可以干净地安装(我们有一个多实例产品) 问题出现在卸载过程中CreateFSRe

我很难理解如何正确安装和卸载自定义操作,以及回滚的目的是什么。我有一个名为
CreateFSRegistryLink
的自定义操作,它创建一个
REG\u链接
注册表项(MSI/InstallShield不能直接在AIK中创建)。我认为这在很大程度上是正常运行的,因为如果链接已经存在,它只会返回
ERROR\u FUNCTION\u NOT\u CALLED
,MSI似乎能很好地处理它,继续安装的其余部分。这确保了产品的多个实例可以干净地安装(我们有一个多实例产品)

问题出现在卸载过程中
CreateFSRegistryLink
似乎在非回滚模式下再次运行。从MSI日志中,我可以看到它在安装期间正常运行,但在卸载期间也会运行:

我正在使用以下选项检查模式:

if (!MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK))
当条件为true时,我会记录一条消息,“CreateFSRegistryLink正在非回滚模式下运行”。当条件为false时,我会记录一条消息,“CreateFSRegistryLink正在回滚模式下运行,因此被跳过。”我从未看到第二条消息显示在日志中

我有
CreateFSRegistryLink
设置了“系统上下文中的延迟执行”的脚本内执行。我还有另一个自定义操作
DeleteFSRegistryLink
设置了“系统上下文中的回滚执行”的脚本内执行。我看到它在安装过程中被跳过,但在卸载过程中没有(我怀疑它在卸载过程中正常运行,但没有添加日志来确认这一点)


我还有一个自定义操作
CountOtherFSSystems
,它将FS\u SystemCount设置为当前实例之外的系统(实例)数。我将
deletefsrigsrylink
设置为只有在
FS\u SystemCount这是我的MSI“必读”列表中的一个条件时才运行,这是一个很好的开始:

其理念是MSI所做的每一项更改都应该是事务性的。在安装、升级、修复或卸载过程中,您应该能够在出现故障时回滚状态更改

有时,您会遇到一个API,而这是不可能的。例如,删除用户帐户或与旧的IIS元数据库API交互。如果API不支持.commit().rollback()功能,那么您只需在提交阶段执行中进行更改。考虑到可以通过禁用回滚来禁用提交阶段,您必须在这些场景中尽早执行

把白皮书读几遍,稍微消化一下,然后继续问你还有什么问题

编辑:这就是我设置自定义操作的方式:

  • CountOtherFSSystems在安装后立即运行Initialize可在所有情况下将FS_SystemCount设置为已安装的其他实例数

  • ROLLBACKSREGISTRYLINK在CountOtherFSSystems之后在系统上下文中以回滚执行的方式运行,条件是抛出2美分:问题似乎与自定义操作条件有关。关于调用MsiGetMode以查看是否是回滚,为什么要麻烦呢?将回滚自定义操作排序在实际延迟CA之前,根据定义,只有在调用原始自定义操作时才会调用该操作,并且该操作被定义为回滚CA且不需要任何条件。您的卸载CA可能与回滚CA相同,但严格来说,卸载CA可以假定其对应的安装CA工作正常,前提是其编码正确且失败导致安装失败,然而,回滚CA可能需要假设安装CA可能仅部分工作,并且需要检查更多系统状态

    如果在卸载时调用CreateRegistryFSLink,则该CA上的条件不正确

    如果您的代码做了或没有做什么,那么由您来记住它做了什么,回滚CA将撤消它

    其余部分似乎与自定义操作的条件有关。如果希望仅在卸载产品时调用一个,请使用REMOVE=“ALL”。如果您有专门与功能或组件卸载相关的CA,则(如Chris所说)使用组件或功能条件,它们如下所示:

    如果希望卸载CA在产品未升级时运行,则REMOVE=“ALL”和not UPGRADINGPRODUCTCODE将起作用


    因此,如果您仍然感到困惑,发布您对CA的定义,特别是条件和类型,可能会有所帮助

    回滚自定义操作在延迟的自定义操作之前“已计划”(写入安装脚本)。稍后在InstallFinalize中,将执行安装脚本,如果出现故障,MSI将引导它向后执行计划的回滚操作。您的问题似乎基于回滚与卸载相关的假设。事实并非如此。它发生在事务期间的故障之后。这意味着允许您撤消以前开始的操作,并且每个安装和卸载都有事务。@MichaelUrman正是这样。我试图弄清楚,如果回滚不是用来确定卸载过程中发生什么的机制,那么什么是确定卸载过程中发生什么的机制。根据答案,我得出结论,可以将条件应用于自定义操作,以确保它们仅在安装期间或卸载期间或其他时间执行。请确保签出:@BlueMonkMN:许多人使用条件仅在“安装”或“卸载”期间执行其部分操作,这就增加了MSI创作的复杂性。我目前对可重用操作的偏好是在MSI中使它们成为无条件的,并使用、MsiGetMode和表数据来确定它们需要做什么(imme)
    MSI (s) (08:CC) [09:42:23:708]: Executing op: CustomActionSchedule(Action=DeleteFSRegistryLink,ActionType=3329,Source=BinaryData,Target=DeleteFSRegistryLink,)
    
    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.