如何添加仅在卸载时发生的 WiX 自定义操作(通过 MSI)?

问题描述 投票:0回答:8

我想修改 MSI 安装程序(通过 WiX 创建)以在卸载时删除整个目录。

我了解 WiX 中的

RemoveFile
RemoveFolder
选项,但这些选项不够强大,无法递归删除包含安装后创建的内容的整个文件夹。

我注意到类似的堆栈溢出问题卸载 WiX 时删除文件,但我想知道是否可以通过调用批处理脚本来删除文件夹来更简单地完成此操作。

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

wix windows-installer custom-action
8个回答
207
投票

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


这个话题困扰了我很久。我终于弄明白了。 网上有一些解决方案,但没有一个真正有效。当然,没有文档。 因此,在下面的图表中,有几个建议使用的属性以及它们针对各种安装场景的值:

alt text

因此,就我而言,我想要一个仅在卸载时运行的 CA,而不是升级、修复或修改。根据上表我必须使用

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

而且成功了!


171
投票

yaluna 的答案存在多个问题,属性名称也区分大小写,

Installed
是正确的拼写(
INSTALLED
不起作用)。 上面的表格应该是这样的:

enter image description here

还假设完全修复并卸载属性的实际值可能是:

enter image description here

WiX 表达式语法文档说:

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

这些属性记录在 Windows 安装程序指南中(例如 Installed

编辑:对第一个表进行小修正;显然,“卸载”也可能发生在

REMOVE
True
的情况下。


54
投票

您可以通过自定义操作来完成此操作。您可以在

<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 提示符”窗口闪烁当您的安装程序运行时。


42
投票

批处理脚本的最大问题是当用户单击“取消”(或安装过程中出现问题)时处理回滚。处理这种情况的正确方法是创建一个将临时行添加到RemoveFiles 表中的CustomAction。这样,Windows Installer 就会为您处理回滚情况。当你看到解决方案时,它变得非常简单。

无论如何,要仅在卸载期间执行操作,请添加一个条件元素:

REMOVE ~= "ALL"

~= 表示比较不区分大小写(尽管我认为 ALL 总是大写)。有关更多信息,请参阅有关条件语法的 MSI SDK 文档

PS:我从来没有坐下来思考过,“哦,安装包中的批处理文件将是一个很好的解决方案。”事实上,找到一个包含批处理文件的安装包只会鼓励我退货退款。


18
投票

这是我制作的一组属性,使用起来比内置的东西更直观。这些条件基于 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>

问题:


1
投票

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

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

0
投票

我使用了在 C++ DLL 中单独编码的自定义操作,并使用 DLL 使用以下语法在卸载时调用适当的函数:

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

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


0
投票

因为我不得不解决同样的问题,所以适用于我的 Wix v5 的版本是:

    <InstallExecuteSequence>
       <Custom Action="DeleteFolderAction" Before="RemoveFiles" Condition="REMOVE"/>
    </InstallExecuteSequence>
© www.soinside.com 2019 - 2024. All rights reserved.