PowerToys 开发规范全解:依赖许可、代码签名、性能测量与测试要求
本文基于 PowerToys 仓库中的官方开发指南 doc/devdocs/development/guidelines.md 展开,系统讲解 Microsoft PowerToys 对第三方依赖引入、代码签名、性能测量、依赖升级、测试要求以及 PR 与发布流程的全部规范。读完本文,你将理解一个新模块从引入外部库到进入发布签核的完整约束链路,并能在仓库中找到每条规范对应的实现与配置证据。
一、开源包与第三方库的引入规范
PowerToys 对引入开源依赖有明确的许可与安全双重门槛,这是该仓库开发规范中最基础的部分。
许可证要求
- MIT 许可通常可以被接受,可以直接引入项目;
- 任何非 MIT 许可的包,都必须先与 PM(产品管理)团队二次确认;
- 所有外部包或项目都必须在 NOTICE.md 中登记。当前仓库的 NOTICE.md 已按模块逐一列出第三方来源与完整许可证文本,例如 Color Picker 模块引用的 Martin Chrzan's Color Picker(MIT License)就在其中完整披露,共覆盖 Color Picker、Command Palette、ImageResizer、PowerToys Run、Installer/Runner、Peek 等十余个模块的第三方材料;
- 即使某许可本身允许自由使用,规范仍建议与团队确认后再引入。
安全与质量要求
规范特别强调引入代码前必须评估其安全性,原因直指 PowerToys 的发布流水线:流水线会用微软证书对外部 DLL 进行签名。一条具体而重要的推论是——如果引入了不安全或质量不佳的代码,它同样会被微软证书签名,一旦出问题造成的影响会被放大。因此规范给出三条实操准则:
- 确保所引入的代码本身是安全可用的;
- 避免使用使用面很窄、不流行的仓库或包;
- 优先选择下载量/使用量大、口碑评分好的包。
这一"签名放大风险"的视角,是理解 PowerToys 后续代码签名规范的背景。
二、代码签名:所有 DLL 与可执行文件必须签名
签名 JSON 文件的维护方式
签名清单(signing JSON 文件)的修改通常是手工进行的,触发场景有两类:
- 新增 DLL 时:无论是 PowerToys 内部模块产生的 DLL,还是外部引入的库;
- 发布流水线报错时:当流水线以"未签名 DLL/可执行文件列表"失败时——
- 若是 PowerToys 自身的 DLL,直接手动将其加入签名列表;
- 若是外部 DLL,必须先验证其安全可签名,再纳入清单。
文件签名的硬性要求
- 所有 DLL 和可执行文件都必须签名,没有例外;
- 新增文件必须补充进签名配置;
- CI 会检查所有文件是否已签名,未签名文件会导致流水线失败;
- 即使是微软自身提供的依赖,如果它尚未签名,也会被纳入签名流程。
从仓库结构看,模块以独立 DLL 动态加载的方式集成(见下文性能测量部分),模块产物 DLL 数量众多,这使得"新增 DLL 必须同步更新签名清单"成为发布过程中高频、必须遵守的操作。
三、性能测量:Stopwatch、日志与模块加载开销
开发指南对性能测量给出了坦率的现状描述,这部分内容对理解 PowerToys 启动行为很有价值。
现状:没有内建启动计时器
- 当前仓库没有内建的定时器来度量 PowerToys 的启动时间;
- 指南提出可改进的方案:在 runner 的
main方法开始处、以及所有模块接口 DLL 加载完成之后各埋一个测量点; - 替代手段是直接使用性能分析器(Profiler)或 Visual Studio 内置的 Profiler;
- 目前没有专门的性能仪表盘或专用测量工具。
启动耗时来自哪里:约 20 个模块接口 DLL
指南指出启动当前需要一定时间,原因是:
- 大约 20 个模块接口 DLL 需要被逐一加载;
- 部分模块在加载阶段即被启动。
这一点可以从 runner 的源码得到印证:powertoy_module.cpp 中的 load_powertoy 函数对每个模块执行 LoadLibraryW(filename) 动态加载接口 DLL,随后通过 GetProcAddress 取出导出符号 powertoy_create 来构造模块实例。每个模块都走一次 Win32 动态库加载路径,这正是"约 20 个模块接口 DLL"造成启动开销的直接机制。
现有的性能数据获取方式
- 代码中使用
System.Diagnostics.Stopwatch进行计时,仓库中大量模块(如 PowerLauncher、Command Palette、Settings.UI、Peek 等)都可直接检索到Stopwatch的使用; - 性能数据写入 PowerToys 的默认日志,排查性能问题时可以按日志中的 stopwatch 相关消息进行检索定位;
- 部分遥测事件也携带性能信息,可作为辅助数据源。
四、依赖管理:WinRT SDK、CsWinRT 与 WebView2
WinRT SDK 与 CsWinRT 的周期性升级
- WinRT SDK 与 CsWinRT 的更新是周期性进行的;
- 两者版本相互牵制:WinRT SDK 往往要求更高版本的 CsWinRT,反之亦然;
- 新版本可在 NuGet.org 或 Visual Studio 的 NuGet Package Explorer 中查看;
- 稳定版优先于预览版;
- 最佳实践是在发布周期早期就升级,以便尽早暴露可能的回归。
仓库的 Directory.Packages.props 中可以看到这条规范的直接体现:
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.250303.1" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.4022.49" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll
at the same version contained inside the NET SDK we're currently building on CI. -->
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
注释明确写出:CsWinRT 的版本必须与 CI 构建所用 .NET SDK 内置的 WinRT.Runtime.dll 版本保持一致——这正是文档所述"WinRT SDK 与 CsWinRT 相互牵制"在仓库中的具体落地,说明升级时不能孤立地只改其中一个版本。
WebView2
- WebView2 用于 Monacoo/Monaco 文件预览等组件(见 src/Monaco 的 Monaco 编辑器集成);
- WebView2 SDK 的版本与 Windows 中的 WebView 运行时相关联。历史上曾因 Windows Update 安装新版 WebView 运行时引发问题,现在 WebView 团队已将 PowerToys 的测试纳入其发布周期;
- 升级 WebView2 的固定流程:
- 更新版本号;
- 提交 PR;
- 对所有使用 WebView2 的组件做 sanity check(正常性验证)。
通用依赖更新流程
- 通过 Visual Studio 更新时,依赖会被自动联动更新;
- 更新完成后必须执行三步:
- Clean build(干净构建);
- Sanity check 确认所有模块仍然正常工作;
- 提交包含变更的 PR。
五、测试要求:多机、多屏与 Fuzzing
Mouse Without Borders 需要多台物理计算机
- 该模块必须使用多台物理计算机才能正确测试;
- 不建议用虚拟机测试,因为宿主与来宾之间的鼠标输入容易造成混淆;
- 至少需要 2 台计算机,有时会用到 3 台;
- 测试通常指派给已知拥有多台计算机的团队成员。
多显示器要求
- 部分工具(如 FancyZones、鼠标类模块)需要多显示器环境测试;
- 建议至少 2 台显示器;
- 其中一台应能使用不同的 DPI 设置,以覆盖混合 DPI 场景。
Fuzzing 测试:安全团队的硬性要求
- 对处理文件 I/O 或用户输入的模块,安全团队要求必须做 fuzzing 测试;
- Fuzzing 通过向程序投喂随机、非法或意料之外的数据来发现漏洞与缺陷;
- PowerToys 集成了微软的 OneFuzz 服务做自动化测试;
- .NET(C#)与 C++ 模块采用不同的 fuzzing 实现路径(.NET 走 OneFuzz 的 .NET fuzzer,C++ 走 libFuzzer);
- 新模块若处理文件 I/O 或用户输入,应当实现 fuzzing 测试;
- 详细配置(包括
OneFuzzConfig.json的字段说明与示例)见仓库内专文 Fuzzing Testing in PowerToys。
发布候选(RC)测试中的 Bug 处理流程
在 release candidate 测试阶段报告 bug 时,遵循固定的五步流程:
- 在团队聊天中讨论;
- 判断是否为回归(确认 bug 在上一版本中是否存在);
- 检查是否已有相同 issue 打开;
- 如需要,新开 issue;
- 如果是回归,决定其对本次发布的严重程度(criticality)。
发布测试与签核(Sign-off)
- 团队按发布检查清单执行,其中包括 WinGet 配置的测试;
- 签核流程:
- 各 Teams 对自己负责的模块独立签核;
- 首个 RC 中发现的回归会产生 PR 修复;
- 第二个 RC 验证修复是否生效;
- Command Palette 需要单独签核;
- 最终验证确保各模块与 Command Palette 集成时不会崩溃。
六、PR 管理与发布流程
PR 评审机制
- PM 团队通常会给 PR 打上 "need review" 标签以引起注意;
- 不改变太多内容的社区小修复通常会被直接接受;
- PM 会设置优先级(有时使用 "info.90" 之类的标签),并决定哪些 PR 优先处理;
- 在时间允许的情况下,团队成员可以帮助推动 PR 合入。
审批要求
- PR 合并前必须获得 code owners 的批准;
- 新团队成员可以审批 PR,但最终批准权在 code owners 手中。
优先级处理
- 优先级不高的老 PR 有时会"被遗漏"(slip through the cracks);
- PM 会用 "priority one" 标签标注必须进入本次发布的 PR;
- Draft(草稿)PR 通常不会被优先处理。
特定类型的 PR
- CI 相关 PR 需要评审并经过 code owner 批准;
- 功能新增(如 GPO 支持)需要 PM 先决定该功能是否被需要;
- 与 Watson 错误相关的 bug 修复有时没有对应的 issue 链接;
- Command Palette 被视为即将发布的版本中的高优先级项目。
七、项目管理注意事项
指南最后给出了主干(main 分支)管理方面的纪律性要求:
- 不要把未完成的功能合入 main;
- 进行中的工作应使用 feature 分支,命名约定为
feature/name-of-feature; - 涉及安装器文件(installer files)的 PR 必须仔细评审——仓库中 installer/ 目录下的 .wxs 组件、Bootstrapper wixproj 等都属于这一敏感范围;
- 未完成的功能要么等完成后再合并,要么置于实验性开关(experimentation flags)之后才允许进入 main。
小结
PowerToys 的开发规范围绕三条主线展开:供应链安全(MIT 优先 + NOTICE.md 登记 + 全量代码签名 + CI 签名检查)、发布质量(干净构建 + 模块 sanity check + 双 RC 回归验证 + 分模块签核)、基础设施要求(多机/多屏测试、OneFuzz 模糊测试、CsWinRT 与 .NET SDK 的运行时版本对齐)。结合仓库中 src/runner/powertoy_module.cpp 的模块动态加载实现、Directory.Packages.props 的版本约束注释以及 doc/devdocs/tools/fuzzingtesting.md 的 fuzzing 配置,这些规范在代码层面均有可验证的对应物。对于希望参与 PowerToys 开发或理解其工程质量体系的读者,这份指南及其关联文档是最直接的切入点。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00