- 开发工具
- 构建工具
【免费下载链接】wix3
WiX Toolset v3.x
本文基于 WiX Toolset v3 官方文档《Creating a Simple WiX Extension》,带你完整走通扩展开发的第一步:创建一个继承自WixExtension的骨架扩展程序集,并用-ext开关在 Candle 和 Light 上完成验证。读完本文,你将掌握骨架扩展的 6 个构建步骤、-ext参数在candle.cs/light.cs中的真实解析与加载链路、WixExtension.Load支持的 5 种程序集定位方式,以及仓库内ValidatorExampleExtension这一可对照的完整样例。
一、WiX 扩展是什么,从哪里开始
WiX 扩展用于扩展和定制 WiX 构建的内容与构建的方式。扩展的入口点是一个继承自WixExtension类的 C# 类,它是所有扩展实现(编译器钩子、绑定器钩子、验证器、命令行参数解析等)的容器。
要理解扩展机制,最直接的读物是 WiX 源码中的 WixExtension 基类。从源码结构看,该类全部成员均为virtual且默认返回null——这意味着一个“什么都不做”的空子类也是合法的扩展,这正是骨架扩展能够直接通过 Candle/Light 验证的原因。
二、六步创建骨架 WiX 扩展
以下步骤完整继承自官方文档,并补充了与仓库源码对照的工程细节。
第 1 步:创建 C# 类库项目
在 Visual Studio 中创建一个名为SampleWixExtension的新 C# 类库(.dll)项目。扩展必须是类库而非可执行程序——仓库内的真实扩展工程 ValidatorExampleExtension.csproj 也明确设置了<OutputType>Library</OutputType>。
第 2 步:引用 wix.dll
为项目添加对wix.dll的引用。在仓库源码工程里对应的写法是 ProjectReference:
<Reference Include="System" /> <Reference Include="System.Xml" /> <ProjectReference Include="..\..\..\Wix\Wix.csproj" />外部开发者则直接引用安装好的 WiX SDK 中的wix.dll即可。
第 3 步:引入命名空间
添加指向核心命名空间的 using 语句:
using Microsoft.Tools.WindowsInstallerXml;该命名空间是WixExtension与AssemblyDefaultWixExtensionAttribute的所属命名空间,可在 WixExtension.cs 与 AssemblyDefaultWixExtensionAttribute.cs 中确认。
第 4 步:继承 WixExtension
public class SampleWixExtension : WixExtension {}空类体即可。WixExtension的抽象能力通过虚属性暴露,骨架阶段全部保持默认null实现。
第 5 步:注册默认扩展类型
在项目的AssemblyInfo.cs中添加AssemblyDefaultWixExtensionAttribute:
[assembly: AssemblyDefaultWixExtension(typeof(SampleWixExtension.SampleWixExtension))]这个属性是命令行“只给 DLL 路径、不指定类名”场景下的关键。从源码看,当WixExtension.Load在程序集中找不到显式类名时,会通过Attribute.GetCustomAttribute读取该属性来获取默认扩展类型;若属性不存在,直接抛出InvalidExtensionType异常(见 WixExtension.cs 第 226-235 行)。该属性本身定义于 AssemblyDefaultWixExtensionAttribute.cs,仅允许作用于程序集([AttributeUsage(AttributeTargets.Assembly)])。仓库内的实例可对照 ValidatorExampleExtension 的 AssemblyInfo.cs:
[assembly: AssemblyDefaultWixExtension(typeof(ValidatorExampleExtension))]第 6 步:编译
构建项目,得到SampleWixExtension.dll。虽然此时这个扩展尚不会做任何事,但它已经具备了被 WiX 工具链识别和加载的全部要件。
三、用 -ext 验证骨架:candle.exe 与 light.exe
骨架编译完成后,即可将 DLL 通过-ext开关传给 Candle 和 Light 进行编译/链接:
candle.exe Product.wxs -ext SampleWixExtension.dll light.exe Product.wxs -ext SampleWixExtension.dll这条命令背后的完整调用链可以在仓库源码中逐层验证:
- 命令行解析。
candle.cs在解析参数时遇到ext会将其取值加入extensionList,若-ext后缺少参数则报告TypeSpecificationForExtensionRequired错误(candle.cs 第 344-355 行);light.cs有完全对称的实现(light.cs 第 581-590 行)。 - 扩展加载。Candle 对
extensionList中每一项调用WixExtension.Load(extension),随后把同一个实例同时注册给预处理器和编译器:preprocessor.AddExtension(wixExtension)与compiler.AddExtension(wixExtension)(candle.cs 第 149-156 行)。 - Light 侧的差异。Light 除了加载扩展外,还会利用扩展的
ParseCommandLine消化 light 自身未识别的剩余命令行参数(light.cs 第 142-153 行),并在后续流程中读取扩展提供的本地化资源;此外若扩展提供了CustomBinder,可与命令行-binder指定的类名匹配以替换默认绑定器(light.cs 第 116-121 行)。
只要 candle 与 light 都能正常走完编译与链接流程而没有扩展加载错误,就证明你的骨架扩展在程序集定位、默认扩展类型解析两个环节上均符合要求。
四、WixExtension.Load:-ext 参数到底支持哪些写法
骨架阶段只需给 DLL 路径,但读懂Load的实现有助于排错。WixExtension.Load(WixExtension.cs 第 143-247 行)支持 5 种程序集定位形式:
AssemblyQualifiedName,例如MyExt, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089;AssemblyName,例如MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089;- 绝对路径,例如
C:\MyExtensions\ExtensionAssembly.dll(走Assembly.LoadFrom); - 应用程序目录下的文件名,例如
ExtensionAssembly.dll; - 相对路径,例如
..\..\MyExtensions\ExtensionAssembly.dll。
另有一条通用规则:可以在程序集名前用逗号前缀显式指定扩展类的全名,如"TopNamespace.ContainingClass, C:\MyExtensions\ExtensionAssembly.dll";未指定类名时则回退到第五步的AssemblyDefaultWixExtensionAttribute。加载成功后,Load会校验目标类型必须IsSubclassOf(typeof(WixExtension)),并用Activator.CreateInstance实例化;任何一步失败都会以WixException抛出InvalidExtension或InvalidExtensionType错误,这正是-ext参数写错时你在命令行看到的错误来源。
五、骨架之后:WixExtension 提供的扩展点
WixExtension通过一组虚属性把不同阶段的钩子暴露给扩展,骨架阶段它们全部返回null,后续按需覆盖即可。整理自 WixExtension.cs 的扩展点如下:
| 虚成员 | 用途 |
|---|---|
ParseCommandLine(args, messageHandler) | 解析扩展自定义的命令行参数,返回未被解析的参数集合供其他扩展继续处理 |
CompilerExtension | 提供编译器扩展,在单遍编译的相应时机被调用 |
BinderExtension | 提供绑定器扩展 |
BinderFileManager | 提供绑定器文件管理器 |
CustomBinder | 提供对默认绑定器的完整替换 |
DecompilerExtension | 提供反编译器扩展 |
PreprocessorExtension | 提供预处理器扩展(自定义指令等) |
InspectorExtension | 提供检查器扩展(Light 的 inspector 阶段) |
UnbinderExtension | 提供解绑器扩展(decompile 场景) |
ValidatorExtension | 提供验证器扩展 |
TableDefinitions | 注册扩展自带的内部表定义 |
DefaultCulture | 声明扩展本地化的默认语言 |
GetLibrary(tableDefinitions) | 返回扩展关联的 WiX 库(wixlib),基类默认返回null |
仓库内可运行的完整样例是 ValidatorExampleExtension:它覆盖了InspectorExtension与ValidatorExtension两个属性,并用私有字段对实例做延迟初始化,展示了一个多钩子扩展的典型组织方式——骨架扩展扩展为功能扩展时的形态与它一致。
六、继续深入的两条路径
骨架代码是 WiX 扩展开发的公共基础,完成本文步骤后沿两条主线继续:
- 构建自定义操作:以骨架代码为起点开发 custom action,然后在 WiX 源码中编写对应操作,参见仓库文档 Adding a Custom Action;
- 构建预处理器扩展:完整走一遍扩展(含 XSD schema 与表定义)的构建流程,参见 Creating a Preprocessor Extension。
此外,扩展开发的通用约定(目标框架、schema 编写、RequiredVersion属性等)在 Introduction to Developing WiX Extensions 中有系统说明,其中特别提到:多个同类型扩展之间没有处理顺序保证,扩展之间不能存在排序依赖;并建议扩展开发者在<Wix>元素上实现RequiredVersion属性,以便安装项目作者锁定扩展版本。
七、小结
一个可工作的 WiX 骨架扩展只需要四件事:继承WixExtension的空类、对wix.dll的引用、AssemblyDefaultWixExtensionAttribute的程序集级注册、以及一次成功的candle.exe / light.exe -ext验证。理解了WixExtension.Load的 5 种程序集定位规则与默认扩展属性的回退机制,再配合仓库中ValidatorExampleExtension这一参照实现,即可在骨架之上按需覆盖CompilerExtension、ValidatorExtension等虚属性,逐步长出完整的自定义扩展。
- 开发工具
- 构建工具
【免费下载链接】wix3
WiX Toolset v3.x
相关推荐
终极Ulauncher扩展开发指南:从零开始构建你的第一个Linux启动器插件
终极Ulauncher扩展开发指南:从零开始构建你的第一个Linux启动器插件 Ulauncher是一款功能丰富的Linux应用启动器,通过扩展机制可以极大增强
桌面应用开发工具VSCodium扩展开发入门:从零构建你的第一个插件
VSCodium扩展开发入门:从零构建你的第一个插件 为什么选择VSCodium开发扩展 VSCodium作为Visual Studio Code的开源替代版本
开发工具BlueOcean插件开发入门:从零构建你的第一个扩展
BlueOcean插件开发入门:从零构建你的第一个扩展 BlueOcean是Jenkins的一款革命性插件,为开发者提供现代化、直观的持续集成/持续部署 CI/
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考