WiX Toolset 创建 Bundle 骨架:从空的 `<Bundle>` 到可用的引导程序工程

原创2026-10-03 14:26:01658 阅读
文章标签:开发工具构建工具

WiX Toolset 创建 Bundle 骨架:从空的 <Bundle> 到可用的引导程序工程

本文围绕 WiX Toolset v3.x 的官方文档 Create the Skeleton Bundle Authoring 展开,完整讲解如何搭建一个 Burn Bundle 的最小可运行骨架:从 <Wix> 根元素下的空 <Bundle> 起步,逐步加入 BootstrapperApplicationRef、Chain、Variable 等核心子元素,并辅以仓库源码(src/tools/wix/Compiler.cs、src/tools/wix/Xsd/wix.xsd、src/Setup/Bundle/Bundle.wxs)印证编译与运行时行为。读完本文,你将能独立写出一个结构正确、可被 candle/light 正常编译的 Bundle 骨架,并为下一步接入标准引导程序与安装包链打好基础。

从空的 Bundle 开始

在 WiX Toolset 中,Bundle 的根元素是 <Bundle>,它必须直接位于 <Wix> 元素之下。一个空 Bundle 的骨架代码如下:

<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Bundle>
    <!-- Contents of the bundle goes here -->
  </Bundle>
</Wix>

这是创建 Bundle 的最基本形态。从源码结构看,编译器在 Compiler.cs 中通过 ParseBundleElement 处理 <Wix> 下的 Bundle 子元素;也就是说,任何 Bundle 都必须落在 <Wix> 根命名空间(http://schemas.microsoft.com/wix/2006/wi)之内,这是编译器的基本约束。

加入两个最常用的子元素:BootstrapperApplicationRef 与 Chain

原文档指出,在示例中要往 <Bundle> 中逐步添加以下元素:

作为起步,先加入其中最常见的两个元素:

<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Bundle>
    <BootstrapperApplicationRef />
    <Chain>
    </Chain>
  </Bundle>
</Wix>
  • <BootstrapperApplicationRef> 最终将指向 WiX Toolset 提供的标准 BootstrapperApplication;
  • <Chain> 最终将容纳组成 Bundle 的有序包列表。

Bundle 元素的合法子元素与编译约束

为了写出正确骨架,有必要了解 <Bundle> 的合法内容模型。在编译器 Compiler.cs 的 ParseBundleElement 中,Bundle 的子元素按 switch 分派处理,合法子元素包括:

  • ApprovedExeForElevation
  • BootstrapperApplication / BootstrapperApplicationRef
  • OptionalUpdateRegistration
  • Catalog
  • Chain
  • Container
  • Log
  • Payload / PayloadGroup(按代码上下文推断)
  • Variable
  • Update、RelatedBundle 等

同时,源码还体现了两个重要的结构约束:

  1. BootstrapperApplication 至多一个:baSeen 标志保证 <Bundle> 下只能有一个 BootstrapperApplication 元素(Compiler.cs),否则抛出 TooManyChildren 错误;而 BootstrapperApplicationRef 不参与该唯一性检查,理论上可多次出现;
  2. Chain 至多一个:chainSeen 标志保证 <Bundle> 下只能有一个 Chain 元素(Compiler.cs)。

此外,ParseBundleElement 还要求(Compiler.cs):

  • Version 属性是必填的;
  • UpgradeCode 属性是必填的;
  • 若未提供 Name,编译器会自动生成 GUID 作为 active section 名称,并据此派生日志变量名 WixBundleLog:Setup.log(Compiler.cs)。

所以一个“真正能编译”的骨架通常需要补上这些属性,例如 src/Setup/Bundle/Bundle.wxs 中 WiX 自身安装包的写法:

<Bundle Name='!(loc.ShortProduct) v$(var.WixVersion)' Manufacturer='!(loc.Company)'
        Version='$(var.WixVersion)' UpgradeCode='65E893AD-EDD5-4E7D-80CA-F0F50F383532'
        IconSourceFile='ProjectFile.ico' SplashScreenSourceFile='SplashScreen.bmp'
        AboutUrl='!(loc.SupportUrl)' UpdateUrl='!(loc.UpdateUrl)'
        Compressed='$(var.WixBundleCompressed)'>
    ...
</Bundle>

Variable:为 Bundle 定义引擎变量

原文档把 <Variable> 列为骨架阶段需要了解的元素之一。它用于描述一个要定义的 Burn 引擎变量(见 wix.xsd),典型用法是:

<Bundle>
  <Variable Name="MyVariable" Value="some-value" />
  ...
</Bundle>

Variable 可以出现在 Bundle 中,用于预定义贯穿整个 Burn 引擎会话的变量,供包命令行、条件表达式与自定义引导程序引用。具体变量的语义可进一步参考 bundle_built_in_variables 文档。

下一步:为 BootstrapperApplicationRef 填充内容

骨架完成后,接下来的操作是往 <BootstrapperApplicationRef> 中添加信息,详细步骤见 Author the BootstrapperApplication for a Bundle。这里先给出一个最小可用示例(来自官方文档 authoring_bundle_application.html.md):

<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />

该 Id 来自 WixBalExtension.dll 提供的 WiX Standard Bootstrapper Application。如果标准引导程序不满足需求,也可以编写自定义引导程序 DLL,并通过 BootstrapperApplication 元素指定:

<BootstrapperApplication SourceFile="path\to\ba.dll">
  <Payload SourceFile="path\to\en-us\resources.dll" />
  <PayloadGroupRef Id="ResourceGroupforJapanese" />
</BootstrapperApplication>

若需使用 RtfLicense 这类带许可证界面的标准引导程序,仓库中对应的实现与文档位于 wixstdba 目录;而 Bundle.wxs(src/Setup/Bundle/Bundle.wxs)则展示了如何通过 <BootstrapperApplicationRef> 挂载 BootstrapperCore.config 与自定义 DLL 等附加 Payload。

为 Chain 填充包列表(骨架的最终目的)

<Chain> 的最终用途是承载构成 Bundle 的包。原文档提供两种接法(详见 bundle_author_chain):

方式一:包定义直接写在 Chain 下

<Chain>
    <ExePackage
      SourceFile="path\to\MyPackage.exe"
      DownloadUrl="http://example.com/?mypackage.exe"
      InstallCommand="/q /ACTION=Install"
      RepairCommand="/q ACTION=Repair /hideconsole" />
</Chain>

方式二:通过 PackageGroupRef 引用共享定义

<Chain>
    <PackageGroupRef Id="MyPackage" />
</Chain>

其中 PackageGroupRef 引用定义在别处 <Fragment> 或 WiX 扩展中的 <PackageGroup>,便于多个 Bundle 复用同一组包定义。src/Setup/Bundle/Bundle.wxs 中 WixPackages、NetFx462Redist 的用法即为此模式的实际样例。

总结:从骨架到完整 Bundle 的路线

阶段 关键操作 依据
1 写 <Wix> 根元素 + 空 <Bundle> Compiler.cs
2 加入 <BootstrapperApplicationRef> 与 <Chain> wix.xsd
3 可选:添加 <Variable> 预定义引擎变量 wix.xsd
4 填充 BootstrapperApplicationRef 指向标准/自定义引导程序 authoring_bundle_application
5 在 Chain 下添加包或引用 PackageGroup bundle_author_chain
6 补全 Version、UpgradeCode 等必填属性并编译 Compiler.cs

至此,你已经掌握了 Bundle 骨架的完整编写方式:从最简的空 <Bundle> 出发,加入 BootstrapperApplicationRef 与 Chain,理解 Variable 的用途,并明确了编译器对 Bundle 子元素与必填属性的约束。下一步即可按文档顺序进入引导程序作者指南,让骨架真正具备可执行的安装能力。

登录后查看全文
wix3