包含COM dll和服务的Wix安装程序

时间:2017-12-21 13:12:23

标签: wix windows-installer

我们有一个wix安装项目,可以使用ServiceInstall安装几个COM dll和一个服务。 COM dll还具有使用heat.exe提取的关联注册表项,以避免SelfRegCost出现问题。

然而,这两者似乎有相互矛盾的要求:

  • COM dll注册表项需要'RemoveExistingProducts After =“InstallInitialize”'以避免在安装后卸载时擦除注册表信息,例如如果在升级时修改了dll路径。
  • 服务需要'RemoveExistingProducts After =“InstallExecute”'(或更高版本)以避免在升级时丢失服务帐户凭据。

我已经阅读了大量有关msi,wix,服务和COM的相关问题/答案,但没有找到解决方案。

解决这个问题的正确方法是什么?

编辑:

安装程序使用'automagic'生成的组件GUID,每个组件只有一个文件。唯一的例外是COM dll组件,它们是由热量生成的,即:

<Component ...>
    <File ...>
        <TypeLib ...>
            <Class ...>
            ...
    </file>
    <RegistryValue ... HKCR...>
    ...
</Component>

它有2个自定义操作,它们注册和取消注册COM服务器(exe),因为我无法弄清楚还有什么要做,因为热量无法提取它。

它确实将注册表密钥写入HKCR和HKLM,但没有写入HKCU。

它安装了~20个第三方文件COM文件(.ocx),并且当前已安装到System32中。它还在我们自己的文件夹中安装了许多第三方文件。

然后它将~15个专有的COM dll和一些非COM文件(包括服务)安装到我们自己的文件夹中。

使用Wix'ServiceInstall'和默认帐户'LocalSystem'安装服务,但用户在第一次安装后更改了此服务。我们不知道帐户信息。不幸的是,在许多情况下,服务需要访问网络共享才能读取大图像,因此我不知道这如何适用于内置帐户。

据我所知,没有共享文件。

我同意RemomveExisting AfterInstallFinalize是首选,所以如果我们能够使用COM注册,那就太棒了。

包含帮助文件(chm和pdf 177MB),结束时为250MB。

更新

如果我们使用'AfterInstallFinalize',服务问题就会解决。但是,这给我们留下了COM dll问题。

我们创建了一个测试安装程序,它只安装一个COM dll及其相应的注册表项(TypeLib ...)。

正如预期的那样,升级时如果组件未被修改,它可以正常工作。即dll路径和自动生成的组件guid都没有改变。

但是,如果修改了dll路径,实际上我们安装了一个新组件,然后在安装后删除关联的COM注册表项,可能是RemoveExistingProducts。我们尝试使用自动生成的guid,并硬编码到与之前安装的guid相同的guid。

问题似乎是dll路径发生了变化,但大多数注册表项都没有。例如。所有'class'键都丢失了。当我说'擦除注册表信息'时,这就是我的意思。修复安装会带回COM注册表项。

所以我想我的问题归结为: 我们如何正确安装/更新COM dll,如果文件路径发生更改,则不会卸载COM注册表项?这可能使用REP = AfterInstallFinalize?

3 个答案:

答案 0 :(得分:0)

您应该能够为com组件使用静态GUID,因此安装程序安装它们的位置无关紧要,因为GUID与旧安装程序中的相同。

我相信这样GUID将有两个产品引用,当您的旧安装进入卸载时,它不会删除与COM组件关联的注册表设置,因为它们将有另一个引用。

您必须进入旧的MSI,然后查看为每个COM组件自动生成的GUID。可能最简单的方法是使用dark.exe或使用ORCA反编译旧的MSI。

认为这会起作用,但你必须测试它。首先尝试使用一个COM组件作为概念验证。我不确定它是否会在旧的安装位置留下旧的COM组件。

答案 1 :(得分:0)

您需要更准确地“擦除注册表信息”。如果COM Dll安装程序组件ID不同,则InstallExecute之后的升级将导致较旧的Dll的引用计数(通过安装程序ID)倒计数到零(如果没有其他客户端产品),因此通常会导致组件(因此,Dll和注册表条目)在安装后被删除(因为REP是在安装完所有内容后)。这也很复杂,因为修复可能会注意到升级产品中现在缺少较新的Dll并尝试重新安装。 (如果注册路径已更改,则Heat.exe可能会生成新的安装程序组件ID - 不确定,抱歉。)

如果COM Dll安装程序组件ID相同,它们将被共享,但如果将COM Dll移动到另一个位置,则注册表路径必须不同,但它仍可能引用旧位置。如果是这种情况,您可能需要创建RemoveRegistryValue以在写入新注册表信息之前删除旧注册(RemoveRegistryValues操作在WriteRegistryValues之前)。这是我尝试的方法,但需要注意的是,我不清楚您在注册表中或修复后看到的内容。

正如Brian所说,检查COM Dll的安装程序组件ID,并使用详细的MSI日志执行afterInstallexecute升级。

对于服务凭据,有助于了解背景信息。如果这些凭据是在安装时提供的(WiX ServiceInstall),并且从未改变它是常见的(如果不是太安全),以保证凭据在某处安全并在升级时应用它们。作为实验,修复已安装的产品是否会丢失服务凭据?任何未初始化的ServiceInstall凭据的潜在应用都可能导致该问题。

答案 2 :(得分:0)

简短摘要

我在下面所说的主要是:打破旧的错误状态的链接,其中新旧设置被多个GUID错误指向的文件混淆。每个组件使用一个文件来解决各种引用计数问题。在未来版本中保持GUID稳定 - 使用 WiX的自动GUID功能执行此操作自动。在主要升级期间强制延迟卸载现有产品。您的问题应该得到解决,但请阅读建议的步骤以获得一两个障碍。

建议的步骤

  • 每个组件强制执行一个文件。这解决了各种各样的问题。 There are a few exceptions with multi-file assemblies and some fringe cases
  • 同时应用WiX自动GUID功能,将GUID设置为&#34; *&#34;。这应该有效地处理组件引用计数,以保持它们稳定,直到组件的密钥文件/注册表项的安装位置发生变化(通常不应该,不需要)。
  • 安装到新位置(新文件夹名称)。这是为了#34;开始新鲜&#34;并消除旧版本的任何干扰。对于转到共享位置的组件,这并不总是可行的。如果您进入system32文件夹,只需将组件设置为永久性。如果你去别的地方,请告诉我们。
  • 在InstallFinalize 之后移动RemoveExistingProduct。
  • 对于将来的版本,您应该有一个可行的解决方案。
  • 下行:如果没有&#34;重新安装&#34;您的服务将无法生存。 (重新应用服务凭据和新的安装位置),但从这一点开始,它应该在任何升级后继续存在。你仍然应该测试修复期间发生了什么 - 我不确定(虽然问题已经存在)。
  • 请记住,使用用户凭据安装服务通常是部署反模式,如第12部分所述:How do I avoid common design flaws in my WiX / MSI deployment solution?。您是否有机会将其删除并使其作为 LocalSystem NetworkService LocalService 或其他一些标准帐户运行? (built-in account info - 值得快速阅读?See this as well)。

以下是一些更长篇大论的思考。值得一提的是,我希望。我会留下它,但我希望这个逐步描述更容易消化。

这里已经有了很好的建议。基本上,卸载旧版本可以在卸载新版本之前或之后进行。这显然已经很清楚了。

现在,如果您的组件GUID遵循最佳实践并且在不同版本中保持稳定,那么如果您在InstallFinalize之后放置RemoveExistingProducts,则不会出现上述问题,但您必须100%遵循组件规则(或者您可能会看到丢失的文件升级后和类似的东西)。

了解组件规则的真正含义非常重要。基本上,绝对安装位置(密钥路径)和GUID之间存在1:1映射。如果密钥路径发生更改,则GUID必须更改。如果GUID发生更改,则密钥路径应更改。否则所有这些都应该在各个版本中保持稳定。为了简单和可靠,我喜欢为每个组件使用一个文件用于所有文件 - 这使得升级更容易可靠地实现。也许这种解释更好:Change my component GUID in wix?

在InstallFinalize之后延迟放置RemoveExistingProducts使主要升级基本上作为&#34;补丁&#34; - 只安装新的东西,只删除过时的东西。这可确保您的服务组件不会被卸载并重新安装(这可能会消除您的凭据),而是会安装它包含的任何更高版本的文件。

  • 此处有类似的升级行为说明:MSI Major Upgrade overwriting rules
  • 我写了一篇关于WiX和MSI包中常见问题的摘要。这有点乱,但这里是:How do I avoid common design flaws in my WiX / MSI deployment solution?
  • 以下是一个讨论,说明如果您不为每个组件使用一个文件,通常会发生什么:https://www.symantec.com/connect/forums/upgrade-problem-and-removeexistingproducts。他的问题的解决方案是更改组件GUID和文件名 - 以打破指向旧的错误状态的链接。他设置了与以前版本不同的文件的新密钥路径(以及删除了以前的密钥文件),打破了绝对路径(密钥路径)和GUID之间的1:1链接。重命名和分配新GUID会为文件提供一个新标识&#34; - 它不再与旧国家纠缠在一起。这里有类似的解释:Safely resolving duplicate component GUIDs in Wix
  • 更极端的版本是更改先前版本的安装文件夹的名称。这将要求您重新生成安装到该(子)目录中的所有组件GUID(因为所有绝对路径都已更改)。我在当天测试了这个并且它有效,但是自从我采用单文件每个组件策略以来,它已经多年没有处理过了。它真正解决了各种各样的问题。

我会问一些问题来澄清事情:

  • 此安装程序的文件数量和兆字节数有多大?只是为了感受它的复杂性和易维护性。
  • 有多少个COM文件,它们是您自己的专有文件,还是安装到共享位置的共享文件?
  • 每个组件使用一个文件,还是每个组件安装多个文件?
  • 你写了很多注册数据吗?如果是这样,你怎么写呢?多个组件?你写信给HKCU,HKLM吗?我建议从应用程序本身编写所有HKCU设置,而不是从设置中编写。这将使其与任何部署纠缠分离。它会更加可靠。
  • 如何设置服务凭据?您是通过自定义操作还是通过普通的MSI表安装服务?正如菲尔所说,这对于维修操作很重要。
  • 总体上是否有很多自定义操作,如果有,他们会做什么?

如果不明显,结论是我会准确地按照组件规则100%并在 InstallFinalize 之后放置 RemoveExistingProduct 以使升级表现为补丁。对于大包装,这也可以更快。 如果正确执行此操作,则不应出现您所描述的问题

按照组件规则,您还可以根据需要为产品进行小幅升级。如果你发现了6个你想要的文件,这对商业产品来说至关重要。&#34; hotfix&#34;安装了包含数千个文件的软件包之后。实际上需要极其小心才能完成这项工作,但这是可能的。

如果你到目前为止还没有遵循组件规则,那么最简单的启动方式就是在我看来安装到ProgramFiles中的一个不同的文件夹(打破过去任何罪过的链接),然后设置组件guids自动生成并使用每个组件的单个文件。 WiX的自动生成guid旨在根据ProgramFiles下的安装位置保持稳定。换句话说,如果您以后更改安装位置,所有guids将与之前不同,但在此之前它们保持稳定。的 AUTOMAGIC 即可。如果您非常彻底,这甚至可以进行修补和轻微升级。