我们使用InstallShield为许多非常相似的产品构建安装程序,每个产品都有共享文件停放在供应商目录下的固定目录中。我们认为安装人员应该处理DLL地狱问题。
想象一下,产品A和B都有文件FOO,安装在目录D中.FOO不一定是DLL;它可以是任何文件。
在一个理想的世界中,FOO的两个副本都是相同的,当两个产品都安装时,FOO在D中得到(覆盖)并且一切都很好。这就是当一切都相同时它似乎如何工作。
实际上,A和B可以来自不同代,因此实际上A具有FOO变体A(FOO_a)并且B具有变体FOO_b。如果两个产品都已安装,现在只有FOO_a或FOO_b中的一个会在D中结束,因此A或B中的一个会因为错误的文件而混淆。我对安装程序(和InstallShield)的期望是,对于安装在系统上的每个产品P,引用计数器将保存在某个位置(注册表?),关于每个已安装的文件。因此,当安装A并放置FOO(_a)时,FOO被标记为属于A,并且引用计数设置为1.如果B现在安装时FOO_b与FOO_a相同,则应将FOO标记为属于B ,引用计数递增。如果安装了B,并且FOO_b与FOO_a不同,我希望安装程序抱怨不建议安装不兼容的文件FOO,安装应该中止。卸载产品时,我希望每个已安装文件的引用计数器都会减少,并且只有在引用计数为零时才会删除已安装的文件。
这不是InstallShield的目的。它只是在安装过程中将FOO粉碎到其目标目录中。这实际上和DLL地狱一样。这是安装程序的预期行为吗? InstallShield? Windows?
我们认为我们找了一种方法让InstallShield来管理它,但找不到任何东西。我很高兴让某人知道在哪里正确配置它。或者是InstallShield不能/不会这样做? [如果是这样,我为什么要给他们钱?]
答案 0 :(得分:2)
如果FOO的变体被版本化并且正确累积(这是在共享位置上运行的所有安装技术的关键),并且如果您的组件是共享的,则在两个产品(如果是MSI)中共享相同的GUID,并共享相同的GUID安装位置,然后一切都会工作。由于条件清单的一部分是不真实的,各种不好的事情可能会发生;有些是解决方法,有些是不可恢复的。
一种尺寸适合所有人有时会变得有点混乱,所以通常将问题空间简化为可以解决的问题。在这种情况下,成本是所有安装作者如果想要明确定义的行为,就必须遵循一些规则。
答案 1 :(得分:1)
如果您真的在寻找解决方案,请使用单独的DLL。这很简单可靠,事实上它更容易谈论(正如你提到FOO_a和FOO_b时所证明的那样)。它还可以避免错误消息,这对您的用户没有帮助。
Windows确实有共享DLL的引用计数方案,但它是按照惯例,所以它是不可靠的。如果您曾经有过卸载程序,请询问您是否确实要删除共享组件,现在就知道原因了。
答案 2 :(得分:1)
如果不知道您使用的是哪种安装技术,任何人都无法开始回答您的问题。 InstallShield是一个支持许多不同框架的产品。
Windows仅跟踪DLL文件上的共享引用。 (SharedDllCount)。 Windows Installer(假设您甚至使用它)也跟踪Compoent引用计数。
但是,应该注意(再次 IF 您正在使用Windows Installer),决定覆盖文件的文件成本计算过程实际上与引用计数无关。引用计数在卸载时发挥作用。
假设您使用的是Windows Installer,请查看:
另见:
What happens if the component rules are broken?
这个*是Windows Installer和InstallShield知道如何处理它,假设您正确实现它。任何编程语言都可能被故意滥用和滥用。
答案 3 :(得分:1)
如果您不希望文件是常见的,为什么世界上您将它们放在同一目录中?我宁愿把它们放在不同的位置。现在假设您的FOO_a正在被同一版本的许多程序使用,然后对于您的新程序所需的FOO_b以及稍后可能添加的其他程序,添加另一个类似的公共目录并使用生成名称或其他名称命名它们。
答案 4 :(得分:0)
我相信如果您正在处理基于MSI的纯安装程序,那么引用计数的工作方式是正确的(这将有助于了解A和B是否为基本MSI或InstallScript项目)。在任何情况下,我都会验证A和B安装项目中包含FOO的组件是否已将其设置为密钥文件,并将Shared属性设置为Yes。这应该导致引用计数被正确管理。
关于运行安装程序时应该发生什么,并且它有一个更新版本的共享文件,据我所知,这主要取决于文件是否有版本,是否是较新版本,以及最后一个属性改变了时间戳。如果你正在构建包含与FOO_a不同的FOO_b的B的安装程序,我不确定InstallShield如何知道它会破坏A(我可能是错的,也许它可以)。一种可能的解决方法是使用自定义操作来检查FOO_b是否不同,如果是,则在安装的早期制作现有的副本,然后在流程结束时将其复制回来。