如何使用 WiX Burn MBA 捆绑包在主要升级期间检测当前安装的功能?

2023-11-26

我正在使用 WiX 3.7 的刻录/托管引导程序应用程序功能来创建基于 MBA 的自定义安装程序。对于我的捆绑包链中的每个软件包,在执行 MinorUpdate 时,我可以轻松检测到哪些软件包功能已安装,以确保在升级过程中通过使用引导程序的 WiX 基类中提供的这些事件来维护这些功能选择:DetectPackageComplete, DetectMsiFeature, DetectRelatedBundle, DetectRelatedMsiPackage, DetectComplete.

然而,在 MajorUpgrade 期间,我只看到一种确定安装了哪些软件包的方法,但没有看到如何确定安装了哪些功能,因为 DetectMsiFeature 事件不会触发。我尝试使用MigrateFeatures产品配置上的标志,但这似乎不起作用(或者我没有正确使用它)。

在 WiX 中使用自定义托管引导程序应用程序执行主要升级时,检测/迁移现有功能的正确方法是什么?


一些文件片段:

注意:如果有帮助的话,我可以提供一个包含所有代码的完整工作 VS 解决方案。

Bundle.wxs:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
    <Bundle Name="Bootstrapper1"  Version="1.1.0.0" Manufacturer="Knights Who Say Ni" UpgradeCode="e6fbf160-d1d9-4b38-b293-94d60eae876f" Compressed="yes">    
        <BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost" >
          <Payload SourceFile="$(var.ManagedBootstrapperApplication.TargetPath)" />
          <!-- other files here -->
        </BootstrapperApplicationRef>
        <Chain>      
          <PackageGroupRef Id="NetFx40Web" />
          <MsiPackage SourceFile="$(var.SetupProject1.TargetPath)" EnableFeatureSelection="yes" Vital="yes"  Compressed="yes" />
        </Chain>
    </Bundle>
</Wix>

产品.wxs:

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="SetupProject1" Language="1033" Codepage="1252"
           Version="1.1.0.0" Manufacturer="Knights Who Say Ni" 
           UpgradeCode="5fcd463a-3287-4fdf-bf00-d5d74baeccda">

        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
        <MajorUpgrade AllowSameVersionUpgrades="no" AllowDowngrades="no" MigrateFeatures="yes" DowngradeErrorMessage="Bring me a shrubbery!" />
        <MediaTemplate EmbedCab="yes" />

        <Feature Id="feature_one" Title="Primary Feature" Level="1">      
          <Component Id="CMP_emptyFile1" Guid="{1740AFA6-A98F-482A-B319-A153AA1BEF10}" Directory="INSTALLFOLDER">
            <File Id="file_emptyFile1" Checksum="yes" KeyPath="yes" Source="TextFile1.txt" />
          </Component>      
        </Feature>
        <Feature Id="feature_Two" Title="Optional Feature" Level="2">
          <Component Id="CMP_emptyFile2" Guid="{F0831C98-AF35-4F5E-BE9A-2F5E3ECF893C}" Directory="INSTALLFOLDER">
            <File Id="file_emptyFile2" Checksum="yes" KeyPath="yes" Source="TextFile2.txt"  />
          </Component>
        </Feature>    
    </Product>
</Wix>

自定义Bootstrapper.cs

public class CustomBootstrapperApplication : BootstrapperApplication {        
    protected override void Run() {
            DetectPackageComplete += HandlePackageDetected;
            DetectMsiFeature += HandleFeatureDetected;
            DetectRelatedBundle += HandleExistingBundleDetected;
            DetectRelatedMsiPackage += HandleExistingPackageDetected;
            DetectComplete += HandleDetectComplete;
            this.Engine.Detect();
            //blocks here until DetectComplete fires...
    }

    private void HandleExistingPackageDetected(object sender, DetectRelatedMsiPackageEventArgs e) {
        Log(string.Format("Detected Related Package {2} ({1}) at version {3} which is a {0}",
            e.Operation, e.PackageId, e.ProductCode, e.Version));
    }

    private void HandleExistingBundleDetected(object sender, DetectRelatedBundleEventArgs e) {
        Log(string.Format("Detected Related {2} Bundle {0} at version {1} which is a {3}",
            e.ProductCode, e.Version, e.RelationType, e.Operation));
    }

    private void HandleFeatureDetected(object sender, DetectMsiFeatureEventArgs e) {
        Log(string.Format("Feature {0} from Package {1} detected in state {2}",
            e.FeatureId, e.PackageId, e.State));
    }

    private void HandlePackageDetected(object sender, DetectPackageCompleteEventArgs e) {
        Log(string.Format("Package {0} Detected in State {1}",
            e.PackageId, e.State));
    }

    private void HandleDetectComplete(object sender, DetectCompleteEventArgs e)
    { /* release the main thread to continue with work */ }

}

升级输出:

请注意,该软件包和两个功能均在 v1.0.0 上安装,并在“缺席”状态下检测到。检测到相关包,但不包含功能详细信息。



Detected Related Upgrade Bundle {5eff0a3c-4b0d-4fd9-875f-05117c07f373) at version 1.0.0.0 which is a MajorUpgrade
Package NetFx4OWeb Detected in State Present
Detected Related Package {540AE32D-75C0-4BF3-A72D-ADBE97FSFF3E} (SetupProject1.msi) at version 1.0.0.0 which is a MajorUpgrade
Feature feature_one from Package SetupProjectl.msi detected in state Absent
Feature feature_Two from Package SetupProjecti .msi detected in state Absent
Package SetupProject1.msi Detected in State Absent
  

我正在标记鲍勃·阿恩森的回应作为答案,因为它给了我推动这个过程所需的东西,但对于看到这篇文章的其他人,我想我会更详细地介绍如何使用 WiX 提供的收集功能状态ProductInstallation类(可在 WiX SDK 中的 Microsoft.Deployment.WindowsInstaller.dll 程序集中找到),从而无需自己直接调用本机 MSI API。

这是可以注册到的方法的示例DetectRelatedMsiPackage事件。请注意,您需要存储收集的信息,以便您可以在计划阶段设置适当的状态。

private void DetectRelatedMsiPackageHandler(object sender, DetectRelatedMsiPackageEventArgs e)
{
    var existingPackageProductCode = e.ProductCode;
    var actionToBeAppliedToExistingPackage = e.Operation;
    var existingPackageId = e.PackageId;
    var existingPackageVersion = e.Version;

    Log(string.Format("Detected existing related package {0} (product: {1}) at version {2}, which will be {3}",
                      existingPackageId, existingPackageProductCode, existingPackageVersion,
                      actionToBeAppliedToExistingPackage));

    if (actionToBeAppliedToExistingPackage == RelatedOperation.MajorUpgrade)
    {

        //requires reference to WiX Toolset\SDK\Microsoft.Deployment.WindowsInstaller.dll
        var installedPackage = new Microsoft.Deployment.WindowsInstaller.ProductInstallation(existingPackageProductCode);
        if (!installedPackage.IsInstalled) {
            Log(string.Format("Migrating Package {0}, which is not installed, so marking it and it's features as Absent", existingPackageId));
            //TODO: add logic to store state so that during Plan phase can set package with package with product code = existingPackageProductCode to PackageState.Absent
        } else {
            Log(string.Format("Migrating features for MajorUpgrade of Package {0}", existingPackageId));

            foreach (var currentInstallFeature in installedPackage.Features) {                        
                if (currentInstallFeature.State == InstallState.Local) {
                    Log(string.Format("Migrating feature {1} of Package {0} - marking as Present", existingPackageId, currentInstallFeature.FeatureName));
                    //TODO: add logic to store state so that during Plan phase can set package and feature states based on this info
                } else {
                    Log(string.Format("Migrating feature {1} of Package {0} - marking as Absent", existingPackageId, currentInstallFeature.FeatureName));
                    //TODO: add logic to store state so that during Plan phase can set package and feature states based on this info
                }
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 WiX Burn MBA 捆绑包在主要升级期间检测当前安装的功能? 的相关文章

  • 如何在 Visual Studio 2010 中增强 XAML 设计器?

    当我使用 XAML 设计器时 进入设计器和退出设计器是如此困难和缓慢 当我这样做时 Visual Studio 卡了一段时间 有什么方法可以增强 XAML 设计器和编辑器吗 Ant 保存 XAML 文件时非常慢 这通常意味着您可能有复杂的
  • VB.NET 相当于 C# 属性简写吗?

    是否有与 C 等效的 VB NET public string FirstName get set 我知道你能做到 Public Property name As String Get Return name ToString End Ge
  • 使用Physics.Raycast 和Physics2D.Raycast 检测对象上的点击

    我的场景中有一个空的游戏对象 带有 2D 组件盒碰撞器 我将脚本附加到该游戏对象 void OnMouseDown Debug Log clic 但是当我点击我的游戏对象时 没有任何效果 你有什么想法 如何检测我的盒子碰撞器上的点击 使用光
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 在 Unity 进程和另一个 C# 进程之间进行本地 IPC 的最快方法 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我希望每秒大约 30 次从 C 应用程序向我的 Unity 应用程序传送大量数据 由于 Unity 不支持映射内存和管道 我考虑了 t
  • 在 C# 中循环遍历文件文件夹的最简单方法是什么?

    我尝试编写一个程序 使用包含相关文件路径的配置文件来导航本地文件系统 我的问题是 在 C 中执行文件 I O 这将是从桌面应用程序到服务器并返回 和文件系统导航时使用的最佳实践是什么 我知道如何谷歌 并且找到了几种解决方案 但我想知道各种功
  • C# Dns.GetHostEntry 不返回连接到 WiFi 的移动设备的名称

    我有一个 C 中的 Windows 窗体应用程序 我试图获取列表中所有客户端的主机名 下面给出的是 ra00l 来自此链接的代码示例 GetHostEntry 非常慢 https stackoverflow com questions 99
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • ASP.NET:获取自 1970 年 1 月 1 日以来的毫秒数

    我有一个 ASP NET VB NET 日期 我试图获取自 1970 年 1 月 1 日以来的毫秒数 我尝试在 MSDN 中寻找方法 但找不到任何东西 有谁知道如何做到这一点 从 NET 4 6 开始 该方法ToUnixTimeMillis
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • 未定义的行为或误报

    我 基本上 在野外遇到过以下情况 x x 5 显然 它可以在早期版本的 gcc 下编译干净 在 gcc 4 5 1 下生成警告 据我所知 警告是由 Wsequence point 生成的 所以我的问题是 这是否违反了标准中关于在序列点之间操
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • 如何使用 watin 中的 FileUploadDialogHandler 访问文件上传对话框

    我正在使用 IE8 和 watin 并尝试通过我的网页测试上传文件 我不能简单地使用 set 方法设置上传文件 例如 ie FileUpload Find ById someId Set C Desktop image jpg 因为上传文本
  • 如何使用 Mongodb C# 驱动程序连接多个集合

    我需要将 3 个集合与多个集合合并在一起 lookup我在 C 驱动程序中尝试过 它允许我 lookup用户采集但无法执行秒 lookup用于设置集合 有人可以帮忙吗 db Transactions aggregate lookup fro
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • 有没有办法强制显示工具提示?

    我有一个验证字段的方法 如果无法验证 该字段将被清除并标记为红色 我还希望在框上方弹出一个工具提示 并向用户显示该值无效的消息 有没有办法做到这一点 并且可以控制工具提示显示的时间 我怎样才能让它自己弹出而不是鼠标悬停时弹出 If the
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 当另一个线程可能设置共享布尔标志(最多一次)时,是否可以读取共享布尔标志而不锁定它?

    我希望我的线程能够更优雅地关闭 因此我尝试实现一个简单的信号机制 我不认为我想要一个完全事件驱动的线程 所以我有一个工作人员有一种方法可以使用关键部分优雅地停止它Monitor 相当于C lock我相信 绘图线程 h class Drawi

随机推荐

  • 强制 MapKit 仅使用缓存的地图图块/以编程方式禁用网络

    我们偶然发现了这样一个问题 我们正在开发一款旅行应用程序 为了确保用户不会在我们的应用程序中花费太多漫游费 我们决定实现一个设置选项 供用户仅查看缓存的地图 因此 我们让用户决定是否要从互联网加载地图 或者想要省钱并查看缓存的地图 存储在
  • InternetExplorer.Application 对象和 cookie 容器

    我有以下用 VB NET 编写的控制台应用程序 Sub Main Dim ie As Object CreateObject InternetExplorer Application ie Visible True ie Navigate2
  • Webform 中的 HTML 助手?

    我有一个旧网站 我想使用 HTML 助手之类的东西来生成特殊的 HTML 在本例中为复杂的按钮 我知道这在 ASP NET MVC 中是如何工作的 但我如何在 Webform 而不是 Razor 中做到这一点 我读过有关静态方法的建议 如下
  • 表单提交失败后显示服务器端验证错误

    表单提交失败后如何显示验证消息 API 请求返回 HTTP 400 application problem json 响应 并包含违规行为作为带有字段路径的列表 https www rfc editor org rfc rfc7807 se
  • 在Java中处理文件指针的有效方法? (使用 BufferedReader 和文件指针)

    我有一个每秒更新的日志文件 我需要定期读取日志文件 一旦执行读取 我需要将文件指针位置存储在我读取的最后一行的末尾 并且在下一个定期读取中我应该从该点开始 目前 我正在 Java 中使用随机访问文件并使用getFilePointer 方法来
  • JAR 文件的正确内部结构是什么

    这是一个非常愚蠢的问题 我找不到明确的答案 背景 我正在使用 Eclipse 在 XP 终端上使用 ANT 插件之一 我刚刚开始使用 ANT 在 jar 指令中 我正在设置已完成的 JAR 文件的位置 当我 解压缩 该文件时 我得到以下内容
  • 为什么使用 Instant 将 1582 年之前的 Java 日期转换为 LocalDate 会给出不同的日期?

    考虑这段代码 Date date new SimpleDateFormat MMddyyyy parse 01011500 LocalDate localDateRight LocalDate parse formatter format
  • 插入金钱时使用的 SQL 数据类型

    我正在使用 Oracle SQL 数据库 我必须插入货币值 工资 作为行的一部分 由于某种奇怪的原因 金钱命令不起作用 是否有任何替代方法可以解决这个问题 数据输入格式 00 000 000 CREATE TABLE staff staff
  • 使用 Compact Framework 设置数据网格中的列宽

    我正在尝试设置数据网格中列的宽度 我使用 Compact Framework 2 0 和 C 我尝试了这个 但它给了我一个 超出债券 的错误消息 foreach DataGridColumnStyle vColumnStyle in dat
  • 如何与子进程共享父进程的 numpy 随机状态?

    我在程序开始时设置了 numpy 随机种子 在程序执行期间 我使用多次运行一个函数multiprocessing Process 该函数使用 numpy random 函数来绘制随机数 问题是Process获取当前环境的副本 因此 每个进程
  • 我们如何在React js中使用axios发送OAuth2.0

    我正在解决一个身份验证问题 我必须为我的 React 应用程序实现 OAuth2 0 身份验证 有什么方法可以使用基于 Axios Promise 的库进行身份验证吗 您必须在标头中传递您的令牌 见下文 const instance axi
  • 在 Perl 中比较多个字符串

    我的代码是这样的 if var eq str1 var eq str2 var eq str3 有没有办法优化这个 我想要类似的东西 if var eq str1 str2 str3 根据字符串的内容 正则表达式非常方便 if var st
  • JSON.stringify 深层对象

    我需要一个函数从任何参数构建 JSON 有效字符串 但是 通过不两次添加对象来避免递归问题 通过截断超过给定深度来避免调用堆栈大小问题 一般来说 它应该能够处理大对象 但代价是截断它们 作为参考 此代码失败 var json JSON st
  • Z3:在求解过程中提供随机解

    我尝试了以下代码http rise4fun com z3 tutorial declare const a Int assert gt a 100 check sat get model 结果总是a 101 我需要答案中的一些随机性 它会产
  • pygraphviz ValueError:在路径中找不到程序点[重复]

    这个问题在这里已经有答案了 问题是 我使用的是 Windows7 并且安装了 pygraphviz 库和 Graphviz 应用程序 Graphviz 应用程序位于 C Program Files 中 当我在 python 上运行程序时 出
  • 是否有跨浏览器的方式来压缩页面上的文本?

    我正在寻找一种方法来压缩页面上相对较小的文本区域 以模仿使用非标准字体完成的图形按钮 理想情况下 只有字母会被压扁或变薄 而单词之间的间距或多或少相同 我知道有一些 CSS 属性可以做这样的事情 但它们更关注字母之间的间距 而不是字母本身的
  • HTML 格式的 Python 单元测试报告

    如何生成 HTML 格式的 python 单元测试报告 再次返回答案 报告可以使用 HTMLTestRunner 生成 例如 import random import unittest import HTMLTestRunner class
  • 如何在引导程序中制作固定位置行?

    我有一个类似表格的结构 其中第一个 div class row 充当表的标题 我正在尝试修复它 因此当我向下滚动页面时 用户仍然可以看到列标题 我给它定位 固定 这实现了这一点 但现在 列的宽度被丢弃了 div class containe
  • 如何从匿名类返回值?

    我有以下代码 正如你所看到的方法postTestResults应该返回一个布尔值 现在的问题是在postTestResults我创建一个内部类AsyncHttpResponseHandler我覆盖onSuccess and onFailur
  • 如何使用 WiX Burn MBA 捆绑包在主要升级期间检测当前安装的功能?

    我正在使用 WiX 3 7 的刻录 托管引导程序应用程序功能来创建基于 MBA 的自定义安装程序 对于我的捆绑包链中的每个软件包 在执行 MinorUpdate 时 我可以轻松检测到哪些软件包功能已安装 以确保在升级过程中通过使用引导程序的