带补丁的 MSI 多实例安装

Posted

技术标签:

【中文标题】带补丁的 MSI 多实例安装【英文标题】:MSI multi-instance installation with patches 【发布时间】:2013-02-11 14:25:03 【问题描述】:

我目前在尝试使用根据此处的说明构建的 MST 在多实例场景中使用 MSP(也使用 WiX 构建)修补 MSI(使用 WiX 构建)时遇到困难:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa367797(v=vs.85).aspx

我构建的转换工具:

生成新的 UpgradeCode/ProductCode 属性 更新升级表以使用新的 UpgradeCode 更新 ProductName 属性以包含实例名称 使用包含实例名称的新项目更新 ServiceControl 和快捷方式表 更新目录表以更新包含 INSTALLDIR 行的实例名称的 DefaultDir 列 生成转换摘要信息并写入转换

安装应用了转换的 MSI 似乎可行。我这样调用 msiexec:

msiexec /i <product.msi> TRANSFORMS=<instance.mst> MSINEWINSTANCE=1

但是,修补似乎不起作用。我已尝试按照此处所述应用补丁:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa369528(v=vs.85).aspx

msiexec /p <mypatch.msp> /n product-code

安装程序立即退出并显示“Windows Installer 服务无法安装升级补丁,因为要升级的程序可能丢失,或者升级补丁可能会更新程序的不同版本。”

基础 MSI 已安装,并且已在 WiX 中的 PatchCreation 元素上使用 AllowProductCodeMismatches="yes" 构建补丁。

如何安装补丁?


编辑:在进一步阅读之后,看起来我在做一些不好的事情。我现在已停止更改 UpgradeCode 属性,因为它似乎不需要,而且我自己的工具转换的实例要轻得多。

我还查看了@YanSklyarenko 的博客条目以进行补丁 - 他修改了现有补丁以更改补丁适用的 ProductCode。我试过用类似的代码做同样的事情:

    // Copy original patch
    File.Copy(_patchPath, _newPatchPath, true);

    // Update patch target product code
    using (var patch = new PatchPackage(_patchPath))
    using (var patchForWrite = new Database(_newPatchPath, DatabaseOpenMode.Transact))
    
        var originalProductCode = patch.GetTargetProductCodes().First();
        var productCode = _newProductCode;

        foreach (var transform in patch.GetTransforms())
        
            // Extract/update transforms
            var tempFileName = Path.GetTempFileName();
            var transformFileName = transform + _instanceName;
            patch.ExtractTransform(transform, tempFileName);
            using (var summaryInfo = new SummaryInfo(tempFileName, true))
            
                summaryInfo.RevisionNumber = summaryInfo.RevisionNumber.Replace(originalProductCode, productCodeString);
                summaryInfo.Persist();
            

            // Write transform to new patch
            using (var insertView = patchForWrite.OpenView("INSERT INTO `_Storages` (`Name`,`Data`) VALUES ('0', ?)", transformFileName))
            
                using (var record = new Record(1))
                
                    record.SetStream(1, new FileStream(tempFileName, FileMode.Open));
                    insertView.Execute(record);
                    patchForWrite.Commit();
                
            

            // Add transform to patch properties
            patchForWrite.SummaryInfo.LastSavedBy += ";:" + transformFileName;
        

        // Update patch properties
        patchForWrite.SummaryInfo.Template = patchForWrite.SummaryInfo.Template.Replace(originalProductCode, productCodeString);
        patchForWrite.SummaryInfo.Persist();
    

我在安装补丁时仍然没有任何运气,并且 msiexec 在写入任何日志之前仍然退出。


编辑 2:我仍然没有运气。我试过使用 WiX 实例转换来安装,但补丁仍然不适用。我的 PatchCreation 元素为每个定义的实例定义了 TargetProductCode 元素,并且 AllowProductCodeMismatches 仍然处于打开状态。


编辑 3:听起来 AllowProductCodeMismatches 是一个 MSIMSP 东西,允许在两个不同的产品代码之间跳转以创建补丁而不是验证。目标产品代码必须包含在补丁中。不幸的是,TargetProductCode 元素似乎被忽略了。

http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Re-Multiple-instance-patches-td1559146.html

我在这里不是一个 100% 肯定的人,但我认为一些验证与基于两个图像生成补丁有关,而不是补丁应用程序本身(以老式的方式生成补丁)来自 PCP 文件的 MSIMSP)。如果在补丁变换生成中使用的两个图像没有相同的产品代码并且 ProductID 验证设置为 no,那么您将不会收到错误。否则,在补丁生成过程中会返回一个错误,让您知道您的输入可能无效等

【问题讨论】:

前段时间我发表了一篇关于如何使用 WiX 实现类似功能的文章:ysdevlog.blogspot.com/2011/08/revisited-multiple-instance.html。您可能想尝试一下。 是的,在我自己解决之后,我写了那篇文章来分享我的经验:) 干杯 @YanSklyarenko - 从 WiX 邮件列表中看起来你过去遇到过同样的问题。但是,您使用的是纯 WiX 补丁设置 - 我正在尝试使用补丁创建属性。我原以为 PatchCreation AllowProductCodeMistmatches="yes" 会解决问题,但我仍然收到错误消息。我还有什么需要做的吗? 例如,在您第一次尝试此操作时,您编写了代码以使用目标产品代码更新补丁。如果我最初针对不同的产品代码构建了补丁,我需要为实例更新它吗? 【参考方案1】:

创建补丁涉及遵循多个规则,而不仅仅是匹配产品代码。以下 MSDN 文章更详细地解释了这些规则:http://msdn.microsoft.com/en-us/library/aa367850.aspx

你也可以在 Yan Sklyarenko 链接的文章中看到,同样的规则在一开始也给他带来了问题。

【讨论】:

我们的补丁可以正常安装。但是由于我们更改了多实例安装的产品代码,我很难让 Windows Installer 允许针对不同的产品代码安装补丁。我认为添加 AllowProductCodeMistmatches="yes" 就足够了 - 但似乎不是。【参考方案2】:

我已经设法让它工作了。出于各种原因,我们的原始补丁是使用 PatchCreation 元素创建的。以这种方式创建的转换设置了检查 ProductCode 和 UpgradeCode 的验证。最后,我更新了我的转换以将其关闭,而不是更改每个转换的 ProductCode/UpgradeCode。所以总而言之,使补丁适用于新产品代码:

更新模板 SummaryInfo 属性并将原始 ProductCode 替换为实例 ProductCode 提取转换并将其替换为禁用 ProductCode 和 UpgradeCode 验证的版本

然后安装补丁:

REM This works fine
msiexec /p <patch.msp> /n <ProductCode>

没有对我有用 - 我从日志中收到一条错误消息,指出 Windows Installer 无法创建补丁的临时副本。:

REM DON'T USE THIS!
msiexec /i <ProductCode> PATCH=<patch.msp>

编辑:要禁用的适当验证标志是:

PatchProduct =      0x00020000, // Disables product code matches
PatchUpgradeCode =  0x08000000, // Disables upgrade code matches
PatchMagic =        0x00040000, // Heck knows what this does - but Orca disables this

【讨论】:

以上是关于带补丁的 MSI 多实例安装的主要内容,如果未能解决你的问题,请参考以下文章

win10-MySql免安装版-安装/多实例

开发人员学Linux:CentOS7编译安装MySQL5.17.8多实例及主从复制

2014.2.24 带参数多线程实例

如何查看 MSI 是不是启用了 InstanceTransforms?

多实例数据库应用PSU

多实例数据库应用PSU