MSI卸载不执行用[RunInstaller]标记的Installer类

时间:2009-12-14 14:33:07

标签: c# .net windows-installer

我们正在开发一个MSI安装程序解决方案(不幸的是基于VDPROJ),它将安装我们的服务器应用程序的一个实例。安装程序的设计都支持安装多个实例的概念。这意味着我们编写了一个小实用程序,它接受'stub'MSI,然后输出一个配置的MSI,其中包含唯一的产品代码,产品名称等。产品代码在属性表和摘要信息流中更新。

安装步骤似乎一切正常。我们的两个测试实例AcmeCorp和ZurgCorp并排安装就好了。他们的Windows服务都已注册并按预期运行。

但是,在卸载其中一个实例时,我们遇到了一个非常奇怪的问题。我们首先卸载哪个实例无关紧要。但是我们选择哪一个,卸载将很快进行 - 但是很快就会错过调用我们的.NET Installer子类(用RunInstaller标记并被CustomAction调用)。

卸载将“成功”,MSI将从“添加/删除程序”列表中消失。但Windows服务仍然落伍,因为MSI卸载程序从不运行我们的程序集来删除它!

现在,如果我们继续卸载第二个实例,那么这个将卸载就好了,包括Windows服务。

那么到底是怎么回事?

我闻到某种形式的引用计数。但是哪里?在确保产品代码不同时,我们遵循了这本书。也许我们缺少与Component Id相关的东西?

感谢。

1 个答案:

答案 0 :(得分:1)

这可以被视为黑客,但它解决了这个问题。当然,MSI会对您打算发布补丁或升级产生影响。但对于我们的特定情况,这不是问题,因为升级将始终涉及卸载服务器,然后使用较新的MSI重新安装它。

无论如何,解决方法是: -

使用Orca查看您的MSI。进入名为Component的表格。在此表中有一个名为ComponentId的列。必须更新所有这些值以获得新值(新GUID)。其他列都不重要,具有Component前缀的C__列仅由MSI数据库在内部使用。正如所解释的那样,关键的是ComponentId,因为这是在Windows注册表中存储的(虽然以某种散列/加密形式),并由MSI用于保留引用计数器。

ComponentId列的更多详细信息位于:http://msdn.microsoft.com/en-us/library/aa368007(VS.85).aspx

为了实现自动化,我将改进我们的“Instance MSI Generator”实用程序,基本上为Component表中的每条记录生成一个新的GUID。