如何添加一个 WiX 自定义操作,只发生在卸载(通过 MSI) ?

我想修改 MSI 安装程序(通过 维克斯创建)删除卸载时的整个目录。

我了解 WiX 中的 RemoveFileRemoveFolder选项,但它们不够健壮,不足以递归删除安装后创建了内容的整个文件夹。

我注意到了类似的 Stack Overflow 问题 卸载 WiX 时删除文件,但我想知道这是否可以更简单地使用调用批处理脚本来删除文件夹。

这是我第一次使用 WiX,而且我还在掌握 自定义行动的窍门。在卸载时运行批处理脚本的自定义操作的基本示例是什么?

134942 次浏览

可以通过自定义操作来实现这一点。可以在 <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" />

真正的诀窍是在 Custom Action 上的 Installed AND NOT UPGRADINGPRODUCTCODE条件,没有这个条件,您的操作将在每次升级时运行(因为升级实际上是卸载然后重新安装)。如果您正在删除文件,那么在升级过程中可能不希望使用它。

顺便说一句: 我建议使用类似 C + + 程序的东西来完成这个动作,而不是使用批处理脚本,因为它提供了电源和控制功能——并且在安装程序运行时,您可以防止“ cmd 提示符”窗口闪烁。

批处理脚本的最大问题是在用户单击取消(或者在安装过程中出现错误)时处理回滚。处理此场景的正确方法是创建 CustomAction,该操作将临时行添加到 RemoveFiles 表中。这样 Windows Installer 就能帮你处理撤销案件了。当你看到解决方案的时候,就会觉得简单得不可思议。

无论如何,为了让操作只在卸载期间执行,添加一个条件元素:

REMOVE ~= "ALL"

~ = 说比较不区分大小写(即使我认为 ALL 总是大写)。有关更多信息,请参见 关于条件语法的 MSI SDK 文档

PS: 从来没有一个案例让我坐下来想,“哦,批处理文件在安装包中是一个很好的解决方案。”实际上,找到一个包含批处理文件的安装包只会鼓励我退回产品以获得退款。

编辑 : 也许看看答案 现在就在下面


这个话题一直让人头疼,我终于想明白了。 网上有一些解决方案,但没有一个真正有效,当然也没有文档。 因此,在下面的图表中有几个建议使用的属性,以及它们在各种安装方案中的值:

alt text

所以在我的情况下,我想要一个 CA,将运行只卸载-不升级,不修理或修改。根据上表我必须使用

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

成功了!

Yaluna 的回答有多个问题,而且属性名是区分大小写的,Installed的拼写是正确的(INSTALLED不起作用)。 上面的表格应该是这样的:

enter image description here

还假设一个完整的修复和卸载属性的实际价值可以是:

enter image description here

WiX 表达式语法的文件显示:

在这些表达式中,可以使用属性名(记住它们是区分大小写的)。

有关物业的资料载于 Windows Installer 指引(例如 已安装)

编辑: 对第一个表的小修正; 显然“卸载”也可能发生,只要 REMOVETrue

我单独使用 C + + DLL 编码的 Custom Action,并使用 DLL 在卸载时调用适当的函数,语法如下:

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

使用上面的代码块,我可以在卸载时运行 C + + DLL 中定义的任何函数。 仅供参考,我的卸载功能有关于清除当前用户数据和注册表项的代码。

这里有一组属性,我做的感觉更直观的使用比内置的东西。这些条件基于上面 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>

问题:

若要仅在卸载、修复、升级或安装时执行操作,可以使用:

<Custom Action="ActionName" Before="InstallFinalize"><![CDATA[Installed AND NOT UPGRADINGPRODUCTCODE]]></Custom>