You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用自定义Bootstrapper执行WiX升级及相关问题咨询

关于WiX自定义Bootstrapper升级的问题解答

问题2:你的WiX升级理解是否正确?

你的基础WiX升级配置是正确的,但需要补充Bundle层面的细节:

  • Product ID设为*:每次构建生成新的ProductCode,这是MSI主升级的核心要求(主升级必须使用新ProductCode、相同UpgradeCode)
  • 版本升级到2.0.0:版本号前三位至少有一位高于旧版本,符合WiX主升级的版本规则
  • UpgradeCode保持一致:这是WiX识别同系列产品的唯一标识,确保MajorUpgrade能定位到旧版本
  • MajorUpgrade标签配置:AllowDowngrades="no"防止用户安装旧版本覆盖新版本,Schedule="afterInstallInitialize"的时机合理(初始化后卸载旧版本),AllowSameVersionUpgrades="no"也符合预期(同版本无需升级)

需要注意:MajorUpgrade是处理MSI包的主升级,而你使用的是自定义Bootstrapper(BA),Bundle层面的升级还需要单独协调BA的流程——这也是你当前问题的核心所在。

问题1:如何让主BA知晓旧包卸载完成并继续安装新版本?

你当前的问题是:旧包卸载完成后,主BA直接退出了,没有衔接后续的安装流程。原因是UpgradeUninstall类的OnApplyComplete方法直接调用了BootstrapperDispatcher.InvokeShutdown(),导致整个BA进程终止。

下面提供两种可行的解决方案:

方案1:给UpgradeUninstall添加回调,衔接安装流程

改造UpgradeUninstall类,增加卸载完成的事件通知,让主BA在卸载结束后重新启动安装流程:

  1. 修改UpgradeUninstall.cs,添加卸载完成事件:
public class UpgradeUninstall {
    private BootstrapperApplicationModel _bootStrapperModel;
    // 新增卸载完成事件
    public event EventHandler UninstallCompleted;

    public UpgradeUninstall(BootstrapperApplicationModel model) {
        _bootStrapperModel = model;
    }

    public void PerformSequence() {
        this.WireUpEventHandlers();
        _bootStrapperModel.BootstrapperApplication.Engine.Detect();
    }

    // ... 保留其他原有方法 ...

    private void OnApplyComplete(object sender, ApplyCompleteEventArgs e) {
        // 触发卸载完成事件
        UninstallCompleted?.Invoke(this, EventArgs.Empty);
        BootstrapperDispatcher.InvokeShutdown();
    }
}
  1. 修改Bootstrapper.cs的Run方法,订阅事件并衔接安装:
protected override void Run() {
    BootstrapperDispatcher = Dispatcher.CurrentDispatcher;
    try {
        _model = new BootstrapperApplicationModel(this);
        var uninstall = new UpgradeUninstall(_model);
        if (uninstall.IsUpgradeUninstallation()) {
            // 订阅卸载完成事件,触发安装流程
            uninstall.UninstallCompleted += (s, args) => {
                this.WireUpEventHandlers();
                _model.BootstrapperApplication.Engine.Detect();
                Dispatcher.Run();
            };
            uninstall.PerformSequence();
        } else {
            // 正常显示安装/卸载UI
            this.WireUpEventHandlers();
            _model.BootstrapperApplication.Engine.Detect();
            Dispatcher.Run();
        }
    } catch (Exception ex) {
        _model.BootstrapperApplication.Engine.Log(LogLevel.Error, $"运行错误: {ex.Message}");
        BootstrapperDispatcher.InvokeShutdown();
    }
}

方案2:整合卸载与安装流程到主BA事件处理中

不再拆分UpgradeUninstall,直接在主BA的事件链中处理“先卸载旧包、再安装新包”的逻辑:

  1. 在主BA中记录旧Bundle信息:
private Bundle _oldUpgradeBundle;

private void WireUpEventHandlers() {
    // ... 保留其他事件订阅 ...
    _model.BootstrapperApplication.DetectRelatedBundle += OnDetectRelatedBundle;
    _model.BootstrapperApplication.DetectComplete += OnDetectComplete;
    _model.BootstrapperApplication.ApplyComplete += OnApplyComplete;
}

private void OnDetectRelatedBundle(object sender, DetectRelatedBundleEventArgs e) {
    // 标记需要升级的旧Bundle
    if (e.Action == RelatedBundleAction.Upgrade) {
        _oldUpgradeBundle = e.Bundle;
    }
}
  1. 在DetectComplete中先计划卸载旧包:
private void OnDetectComplete(object sender, DetectCompleteEventArgs e) {
    if (_oldUpgradeBundle != null) {
        // 先计划卸载旧Bundle
        _model.BootstrapperApplication.Engine.Plan(LaunchAction.Uninstall, _oldUpgradeBundle.BundleId);
    } else {
        // 正常计划安装
        _model.PlanAction(LaunchAction.Install);
    }
}
  1. 在ApplyComplete中触发新版本安装:
private void OnApplyComplete(object sender, ApplyCompleteEventArgs e) {
    if (_oldUpgradeBundle != null) {
        // 旧包卸载完成,清除标记并计划安装新版本
        _oldUpgradeBundle = null;
        _model.PlanAction(LaunchAction.Install);
        _model.ApplyAction();
    } else {
        // 安装完成,关闭UI
        BootstrapperDispatcher.InvokeShutdown();
    }
}

额外注意点

你提到的“出现另一个BA实例”的处理逻辑是正确的:通过IsUpgradeUninstallation()判断旧Bundle是静默卸载场景(Display.None/Display.Embedded),直接执行卸载不显示UI,避免弹出旧BA界面。

另外请务必确保Bundle的UpgradeCode也和第1版保持一致——Bundle层面的升级同样依赖UpgradeCode识别同系列包,很多开发者容易忽略这一点。

内容的提问来源于stack exchange,提问作者Mark U

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:58:08