如何使用WiX表达文件依赖项

时间:2018-12-12 07:57:39

标签: wix windows-installer

我有几个MSI文件用于安装不同的应用程序。所有这些软件包都共享相同的基础 runtime ,基本上是一组DLL。该运行时作为合并模块拉入每个安装程序。安装这些软件包中的几个软件包就可以很好地工作,始终将最新版本的运行时保留在系统上,并且当删除最后一个软件包时,所有内容将从系统中删除。

现在,我不得不将其中一个DLL拆分为2个,并向运行时添加了一个新组件,以安装新DLL。这个新的DLL与运行时的其他库链接。现在假设以下情况:

  • 为运行时安装带有合并模块的旧软件包,而无需新的DLL
  • 为运行时安装具有更高版本合并模块的新软件包。现在系统上有2个程序包
  • 再次删除新软件包

现在,旧软件包已损坏,原因是:

  • 新DLL的新组件的引用计数为1,因为旧软件包没有引用,因此被删除了
  • 其他运行时DLL保留在系统上,因为它们仍被较早的程序包引用。但是,由于它们是新的,它们已经与不再存在的新DLL链接

所以我的问题是:

  • 有没有一种方法可以在WiX代码中明确声明文件A依赖于文件B,以便文件A保留在系统上,直到所有引用都被卸载为止。
  • 或者是否有一种方法可以以不再存在依赖性的方式显着降级受抚养人?
  • 我从根本上做错了吗?

我在干净的机器上尝试的操作是遵循SteinÅsmul的建议:

<Component Id='OldLibsNowDependingOnNewLib' Guid='C8DCD2AB-CBE5-4853-9B25-9D6FE1F678DD'>
  <File Id='LibOne' Name='LibOne.dll' Source='$(var.SourceDir)/LibOne.dll' />
  <File Id='LibTwo' Name='LibTwo.dll' Source='$(var.SourceDir)/LibTwo.dll' />
</Component>
<Component Id='NewLibComponent' Guid='CD2DB93D-1952-4788-A537-CE5FFDE5F0C8' Shared='yes'>
  <File Id='LibNew' Name='LibNew.dll' Source='$(var.SourceDir)/LibNew.dll' />
</Component>

但是不幸的是,这并不能改变行为。

1 个答案:

答案 0 :(得分:0)

  

更新:再次查看SDK,我看到组件的标志msidbComponentAttributesShared。这个   看起来很有希望解决您描述的问题。请尝试启用   该标志并重新编译安装程序的版本2(除非它是   直播)。

     

为有问题的组件(最后一部分)启用共享标志

<Component Feature="Product" Shared="yes">

这似乎是对补丁程序的支持,但也许对您的情况也适用。 通过MSI SDK

"If a component is marked with this attribute value in at least one package installed on the system, the installer treats the component as marked in all packages. If a package that shares the marked component is uninstalled, Windows Installer 4.5 can continue to share the highest version of the component on the system, even if that highest version was installed by the package that is being uninstalled."


我认为上面的方法应该有效,但是现在没有时间进行测试。留下以下内容进行审核。


  

简短答案 :使用WiX的Burn(设置链接器)按顺序安装应用程序设置和可以处理的新的单独运行时设置   与您的应用程序安装版本无关。


前提条件设置 :有趣的情况。这就是为什么我喜欢将先决条件拆分为自己的MSI程序包并通过Burn Bundle Bootstrapper进行部署的原因。 Burn是WiX的bootstrapper / downloader / chainer-本质上是按顺序运行多种设置的一种方式-以几种不同的格式,例如MSIEXEMSUMSP。这样做时-将运行时放在自己的MSI中-不会发生纠缠,您可以很好地将运行时文件与特定于应用程序的文件分离。换句话说:您可以使用自己的MSI自行更新运行时文件。这些文件甚至还具有 reference count 1 ,这意味着您可以轻松卸载所有文件(如果您通过还可以包含在其他软件包中-详情见下文)。

合并模块-半静态链接? :以一种奇怪的方式,合并模块属于半静态链接。整个合并模块是一个版本-二进制捆绑包(认为COM)-但其安装行为仅是“较高版本获胜”之一。因此,其中具有最新合并模块的单个更新的MSI将为使用它们的所有应用程序更新共享文件。然后,卸载将执行您所看到的操作:保留由较早的安装程序最初安装的文件。

选项 :您的一个“解决方案”可能是使用较新的合并模块重新编译较旧的设置,然后重新安装,据我所知您不会这样做喜欢。我也不喜欢我想这根本不是解决方案。其他一些建议:

  • 永久组件 :您可以将新文件的托管组件设置为系统上的永久组件。这很容易,但也很愚蠢,并不总是很理想。然后,卸载将完全不会删除该文件。
  • 先决条件 :这是我上面提到的最喜欢的选项。您编译一个先决条件MSI安装程序,以安装运行时组件。该MSI可以向自身提供更新,而不会影响主应用程序。这是我追求的主要好处: Cohesion Coupling 好处。
    • 合并模块 :我会完全避免合并模块,但是通常将相同的合并模块合并到必备设置中-如果您已经有合并模块。
      • 在大多数情况下,合并合并模块很好,因为您先安装必备组件,然后就可以随意安装和卸载应用程序版本,而不会影响运行时,因为其他产品(必备MSI)已安装了运行时-并且该设置应保留后面,不能卸载。
      • 如果合并模块不起作用并带来您已经遇到的冲突,则可以尝试与上述msidbComponentAttributesShared“解决方案”结合使用。到目前为止尚未经过我的测试。建议这样的事情总是冒险,但这是“尽力而为”。
    • WiX包含文件 :我更喜欢使用WiX包含文件,该文件允许我提取新文件而无需重新编写二进制格式的整个合并模块(请考虑C ++包含文件,而不是合并模块的COM样式的二进制重用)。
  • 并排 :许多人喜欢并排安装先决条件,以便多个版本的运行时可以共存。这可能涉及也可能不涉及GAC。切换运行时版本将是清单操作。通常有点令人困惑,但可行。您可以同时使用合并模块和单独的MSI文件来部署此类运行时-如上所述。我肯定会使用必备的MSI。

我现在想不出更多,但我知道这次我忘记了一些重要的事情。让我坚持目前的工作,以防它激发您的想法。

繁琐的先决条件设置 :请注意,先决条件MSI文件对于公司部署而言并不那么糟糕,因为部署系统将允许人们定义MSI文件之间的关系并设置部署链。对于家庭用户,您可以轻松地将所有内容包装在大型setup.exe中。

无意义选项 :没有意义的选项是将新文件滚动到两个安装版本中。没有收获,开销很大。有些人喜欢将新文件本地复制到主安装文件夹中。由于链接到的文件可能在其他位置(运行时位置),因此无法使用。我认为在这种情况下静态链接并不重要。我猜想,这只是解决现场问题的最后手段。设置SharedDllRefCounter flag不会影响MSI参考计数,它是for legacy reference counting(非MSI设置),尽管手动进行调整是一种紧急的“解决方案”。 最后的选择的人们通常会放弃运行时安装,并将所有内容安装到同一安装文件夹中。然后,您必须始终为每个发行版重新编译所有内容-这是您要避免的事情?


某些链接