带有COM dll和服务的Wix安装程序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带有COM dll和服务的Wix安装程序相关的知识,希望对你有一定的参考价值。
我们有一个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”,但用户在首次安装后更改了此项。我们不知道帐户信息。不幸的是,在许多情况下,服务需要访问网络共享以读取大图像,因此我不知道这如何适用于内置帐户。
据我所知,没有共享文件。
我同意删除现有的InstallFinalize是可取的,所以如果我们可以让它与COM注册一起使用,那就太好了。
包括帮助文件(chm和pdf 177MB),它的结尾为250MB。
UPDATE
如果我们使用'AfterInstallFinalize',服务问题是固定的。但是,这给我们留下了COM dll问题。
我们创建了一个测试安装程序,它只安装一个COM dll及其相应的注册表项(TypeLib ...)。
正如预期的那样,升级时如果组件未被修改则工作正常。即dll路径和自动生成的组件guid都保持不变。
但是,如果修改了dll路径,实际上我们安装了一个新组件,然后在安装后删除关联的COM注册表项,可能是RemoveExistingProducts。我们尝试使用自动生成的guid,并硬编码到与之前安装的guid相同的guid。
问题似乎是dll路径发生了变化,但大多数注册表项都没有。例如。所有'class'键都丢失了。当我说'擦除注册表信息'时,这就是我的意思。修复安装会返回COM注册表项。
所以我想我的问题可以归结为:我们如何正确安装/更新COM dll,如果文件路径发生变化,那么COM注册表项是否未安装?这可能使用REP = AfterInstallFinalize吗?
简短的摘要:
我在下面说的主要是:打破旧的错误状态的链接,其中新旧设置混淆了多个GUID错误指向的文件。每个组件使用一个文件来解决各种引用计数问题。在未来版本中保持GUID稳定 - 使用WiX的自动GUID功能自动执行此操作。在主要升级期间强制延迟卸载现有产品。你的问题应该解决,但阅读建议的步骤一两句话。
建议的步骤:
- 每个组件强制执行一个文件。这解决了各种各样的问题。 There are a few exceptions with multi-file assemblies and some fringe cases。
- 同时应用WiX自动GUID功能,将GUID设置为“*”。这应该有效地处理组件引用计数,以保持它们稳定,直到组件的密钥文件/注册表项的安装位置发生更改(通常不应该,不需要)。
- 安装到新位置(新文件夹名称)。这是为了“重新开始”并消除旧版本的任何干扰。对于转到共享位置的组件,这并不总是可行的。如果您进入system32文件夹,只需将组件设置为永久性。如果你去别的地方,请告诉我们。
- 在InstallFinalize之后移动RemoveExistingProduct。
- 对于将来的版本,您应该有一个可行的解决方案。
- 缺点:如果没有“重新安装”(重新应用的服务凭据和新的安装位置),您的服务将无法生存,但从现在开始,它将在任何升级后继续存在。你仍然应该测试修复过程中会发生什么 - 我不确定(虽然问题已经存在)。
- 请记住,使用用户凭据安装服务通常是部署反模式,如第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使主要升级基本上作为“补丁” - 仅安装新的,并仅删除过时的内容。这可确保您的服务组件不会被卸载和重新安装(这可能会消除您的凭据),而是会安装它包含的任何更高版本的文件。
- 这里有类似的升级行为描述: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会为文件提供“新标识” - 它不再与旧状态纠缠在一起。这里有类似的解释:Safely resolving duplicate component GUIDs in Wix。
- 更极端的版本是从先前版本更改安装文件夹的名称。这将要求您重新生成安装到该(子)目录中的所有组件GUID(因为所有绝对路径都已更改)。我在当天测试了这个并且它有效,但是由于我采用了每个组件的单文件策略,所以多年来一直没有处理它。它真的解决了各种各样的问题。
我会问一些问题来澄清事情:
- 这个安装程序的文件数量和兆字节有多大?只是为了感受它的复杂性和易维护性。
- 有多少个COM文件,它们是您自己的专有文件,还是安装到共享位置的共享文件?
- 您是否为每个组件使用一个文件,或者每个组件安装多个文件?
- 你写了很多注册表数据吗?如果是这样,你怎么写呢?多个组件?你写信给HKCU,HKLM吗?我建议从应用程序本身编写所有HKCU设置,而不是从设置中编写。这将使其与任何部署纠缠分离。它会更加可靠。
- 你如何设置服务凭证?您是通过自定义操作还是通过普通的MSI表安装服务?正如Phil所说,这对于修理操作尤为重要。
- 总体上有很多自定义操作,如果有,他们会做什么?
如果不是很明显,那么结论是我将100%准确地遵循组件规则并在InstallFinalize之后放置RemoveExistingProduct以使升级表现为补丁。对于大包装,这也可以更快。如果做得好,不应该出现您描述的问题。
按照组件规则,您还可以为产品进行小幅升级 - 如果需要的话。如果您在安装了包含数千个文件的软件包之后发现了几个要“修补”的文件,这对商业产品至关重要。实际上需要极其小心才能完成这项工作,但这是可能的。
如果你到目前为止还没有遵循组件规则,最简单的方法是在我看来安装到ProgramFiles之前的一个不同的文件夹(打破过去任何罪过的链接),并将组件guids设置为auto-每个组件生成并使用单个文件。 WiX的自动生成guid旨在根据ProgramFiles下的安装位置保持稳定。换句话说,如果您以后更改安装位置,所有guids将与之前不同,但在此之前它们保持稳定。 AUTOMAGIC。如果您非常彻底,这甚至可以进行修补和小修改。
您应该能够为com组件使用静态GUID,因此安装程序安装它们的位置无关紧要,因为GUID与旧安装程序中的GUID相同。
我相信这样GUID将有两个产品引用,当您的旧安装进入卸载时,它不会删除与COM组件关联的注册表设置,因为它们将有另一个引用。
您必须进入旧的MSI,然后查看为每个COM组件自动生成的GUID。可能最简单的方法是使用dark.exe或使用ORCA反编译旧的MSI。
我认为这样可行,但你必须测试它。首先尝试使用一个COM组件作为概念验证。我不确定它是否会在旧的安装位置留下旧的COM组件。
您需要更准确地“擦除注册表信息”。如果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凭据的潜在应用都可能导致该问题。
以上是关于带有COM dll和服务的Wix安装程序的主要内容,如果未能解决你的问题,请参考以下文章