跳转到内容

Windows 开发环境

按自己的方式安装开发工具。mise 是可选项,不是贡献或构建的前提。global.json 选择 .NET SDK;项目清单及锁文件定义依赖,根 package.json 选择 pnpm,.vsconfig 声明 MSVC/Windows SDK 组件。可选的 mise.toml / mise.lock 记录便利的本地工具组合及同一脚本的快捷入口。WinUI Manager 位于 apps/manager-winui;Rust workspace 包含 core 与独立 Runner。Dioxus 及其管理服务、Native E2E 和打包工具链已移除。独立模板 smoke 继续保留在忽略的 target/toolchain-smoke/ 下用于环境诊断。

工具 当前版本或组件 要求/来源
.NET SDK 10.0.400 global.json 要求该版本,并禁止 SDK roll-forward
Rust 1.98.1,rustfmt/clippy 可选 mise 配置中的本地参考工具链;Windows 构建需要 MSVC host;crate 清单和 Cargo.lock 定义 Rust 依赖
PowerShell 本地参考版本 7.6.5 脚本要求 PATH 中存在 PowerShell 7(pwsh),不依赖 Codex 私有运行时
Node / pnpm 本地参考版本 24.18.0 / 11.10.0 pnpm 版本由根 packageManager 声明;用于品牌工具和文档,构建或发布 WinUI 不需要
just 本地参考版本 1.58.0 同一套 Rust/WinUI 命令的可选快捷入口,不是必需工具
WinUI CLI 模板 0.0.6-alpha Install-WinUITemplates.ps1 固定官方预览模板,仅用于独立 smoke 测试
WinUI smoke 依赖 Windows App SDK 2.4.0、SDK.BuildTools 10.0.26100.7705、WinApp 0.3.1 验证脚本固定直接包引用,独立于机器级 Windows SDK
WinUI Manager 组件 WindowsAppSDK.WinUI 2.3.6、InteractiveExperiences 2.1.6、SDK.BuildTools 10.0.26100.7705 对应 Windows App SDK 2.4.0 组件集;NuGet 锁定全部传递依赖
MSVC / Windows SDK VC.Tools.x86.x64 / Windows11SDK.26100 由 .vsconfig 声明;Install-BuildTools.ps1 调用 Microsoft 官方安装器安装系统组件

选择 mise 时,mise.lock 记录 Windows x64 可提供的下载地址/摘要;core .NET/Rust 仍委托官方安装脚本/rustup,锁文件不代表它们的完整离线镜像。MSVC bootstrapper 固定为核验过的 18.9.1 URL/SHA-256,实际组件按 Microsoft 通道解析,并非所有组件都可由 mise 隔离或逐字节锁定。

使用 mise 时,其 .NET core backend 使用共享 SDK 根目录,单独固定工具版本不能替代 .NET 的 SDK resolver,SDK 选择仍以 global.json 为准。mise .NET 管理、Rust 管理

仅构建 WinUI 时,用常用安装器或包管理器安装 PowerShell 7、global.json 指定的 .NET SDK,以及使用 MSVC host 的 Rust。确保 PATH 中有 pwsh、dotnet 和 cargo,然后在仓库根目录执行:

终端窗口
pwsh -NoProfile -File scripts/windows/Install-BuildTools.ps1
pwsh -NoProfile -File scripts/windows/Invoke-WinUI.ps1 -Action Build

这些命令不要求 Node、pnpm、just 或 alpha WinUI 模板。Node/pnpm 单独服务文档与品牌工具;Doctor 检查 .NET、Rust、MSVC 和 Windows SDK,不依赖退役的 Dioxus 工具链:

终端窗口
pwsh -NoProfile -File scripts/windows/Invoke-Build.ps1 -Action Doctor

如需独立模板 smoke 测试:

终端窗口
pwsh -NoProfile -File scripts/windows/Install-WinUITemplates.ps1
pwsh -NoProfile -File scripts/windows/Test-WinUIBuild.ps1

如果偏好 mise,可先审阅配置,再运行 mise trust、mise install,随后使用已有的 mise run windows:* 和 mise run winui:* 别名。这些只是可选快捷入口,不是另一套构建流程。

系统组件安装脚本会验证 bootstrapper 的 SHA-256 和 Microsoft 签名,按 .vsconfig 安装编译器/SDK及其必需依赖;已有完整组件时直接返回。无需安装完整 Visual Studio IDE。Microsoft MSVC 组件安装

Microsoft 安装需要正常 UAC 权限。脚本使用 --norestart,不会自动重启;若退出码为 3010,会明确报告安装完成但需要重启,不能当成未安装,也不能宣称重启已完成。官方安装参数

Invoke-Build.ps1 -Action Doctor 用 vswhere 查找所需组件,再加载官方 Developer PowerShell;不会永久改写系统 PATH,也不会输出全量环境变量。按自己的方式安装 PowerShell 7;脚本不依赖 Windows PowerShell 5.1 或 Codex 的 PATH 注入。Developer PowerShell

WinUI 实现入口:

终端窗口
pwsh -NoProfile -File scripts/windows/Invoke-WinUI.ps1 -Action Test # 配置安全、本地 Steam、Runner 安装及界面语言服务回归
pwsh -NoProfile -File scripts/windows/Test-WinUIContracts.ps1 # C# / Rust 往返、真实 Runner 受控父子进程验证
pwsh -NoProfile -File scripts/windows/Invoke-WinUI.ps1 -Action Build # Release XAML 编译,stage 当前 Rust Runner
pwsh -NoProfile -File scripts/windows/Invoke-WinUI.ps1 -Action Publish # target/winui/publish 自包含目录,含原生资源索引
pwsh -NoProfile -File scripts/windows/Test-WinUINativeUi.ps1 # 实际窗口 UIA 回归;发布后在解锁交互桌面执行
pwsh -NoProfile -File scripts/windows/Invoke-WinUI.ps1 -Action Sandbox # 发布并打开一次性 Steam/用户目录中的原生预览

NuGet 依赖由各项目 packages.lock.json 固定,日常命令使用 locked restore。Application 和部署项目显式列出 win-x64,避免测试与发布轮换时漂移。Host 固定 NativeAOT 依赖;发布先加载既定原生 SDK,再生成独立 GUI 子系统可执行文件。只在有意更新依赖/目标时使用 --force-evaluate,并审查锁文件差异。

Test-WinUINativeUi.ps1 验证已有完整便携目录,构建/运行仅用于开发的控制台 UIA 工具,以新建可丢弃 Steam/用户数据夹具操作实际窗口。它不重新发布 Manager、不操作真实游戏库。-PublishDirectory 可选择具体便携目录;已安装的版本目录会被拒绝。执行需要解锁的交互 Windows 桌面,CI 只编译工具。可选 mise 别名为 winui:native-test。夹具证据保存在 target/winui/native-ui/;覆盖范围和剩余原生门槛见测试。

-Action Test 包含部署回归,-Action Build 编译 Host,但不发布应用包。-Action Publish 也包含 SteamWrapper.Deployment.dll 和 Deployment/SteamWrapper.exe。已验证 Inno 编译器、真实隔离安装测试及本地安装包构建的直接命令见安装器预览指南。可选 mise 别名为 winui:installer-tools、winui:installer-test 和 winui:signing-test。

Manager 已从 Windows App SDK 2.4.0 总包改为上述组件包,保留原组件版本与摘要;InteractiveExperiences 显式固定 2.1.6,避免依赖回落到 2.1.3。AI、ML、Search、Widgets、DWrite 及其未使用发布文件不再进入新产物;独立环境 smoke 仍使用总包,不随此次精简改变。

Manager 使用 Windows App SDK 的 原生 picker API。项目直接维护,不依赖 alpha 模板安装;EnableMsixTooling 用于生成应用 PRI 资源索引,WindowsPackageType=None 并关闭包生成/签名,因此不会注册 MSIX 调试身份。发布检查包含 Manager PRI、.NET、WinUI 和 Runner;只有编译成功不足以证明 XAML 能在启动时加载。

Invoke-WinUI.ps1 -Action Publish 先写入 target/winui/publish-staging-<id> 的全新目录,验证 Manager 程序/程序集、PRI、.NET、WinUI、picker 投影、Runner 与清单,再替换 target/winui/publish。目录操作限于本仓库 target/winui,拒绝重解析路径,发布锁串行处理替换;正在运行的该目录预览会阻止替换。校验失败保留旧版,普通替换失败恢复旧目录;恢复或清理受阻时会报告保留位置。目录重命名不构成断电事务,失败候选保留用于排查。

发布回归直接运行真实发布命令,再用隔离目录验证错误恢复,无需额外测试框架:

终端窗口
pwsh -NoProfile -File scripts/windows/Test-WinUIPublish.ps1
# 只检查目录替换/失败恢复,不重新构建:
pwsh -NoProfile -File scripts/windows/Test-WinUIPublish.ps1 -SkipBuild

完整命令包含 5 项检查:旧哨兵文件不残留、缺失资源保留旧版、锁住候选时回滚、成功替换只含新文件、越界路径拒绝。测试文件均在 target/winui 中;运行前关闭发布目录中的预览。

沙盒每次在 target/winui/sandbox/<id> 创建示例 Steam manifest、LOCALAPPDATA、XDG_DATA_HOME,并设置 STEAMWRAPPER_E2E_ROOT。示例游戏不带真实游戏程序,选择受控测试 exe 即可验证配置。脱离沙盒的产物会尝试使用常规用户数据位置;实际文件视图仍需按下节检查。常规自动化使用沙盒入口。不要从发布目录单独拷出 EXE。

没有已保存的偏好时,界面跟随已支持的系统界面文化,不支持时使用英语;已保存的手动选择优先。侧栏可选择 English / 简体中文。WinUI Manager 使用与 profiles.toml 同级的独立 SteamWrapper/ui-settings.json,其中 language 的规范值为 en-US、zh-CN;兼容 en、zh-SG、zh-Hans,去除首尾空白且不区分大小写。没有键时将 zh-CN、zh-SG 及明确的 zh-Hans 系统文化识别为简体中文;不支持的文化、明确的无效值或无法读取的设置使用英语。读取或仅保存封面偏好不会锁定识别出的语言。成功保存偏好后,界面立即刷新应用自有标签、动态控件、状态和服务错误,保留尚未保存的输入;保存失败保留当前语言和原设置文件。未知 JSON 字段保留,损坏、重复键、非对象或过大的设置文件不会被覆盖。用户名称、路径、参数、协议标识和诊断日志不参与翻译;原生系统对话框中的系统文案沿用系统语言。

WinUI 的中性英文资源和简体中文卫星资源位于 SteamWrapper.Application/Localization。查找资源时显式指定 .NET culture,不依赖系统显示语言,也不修改进程的全局 culture。检查发布目录时,除原有原生资源外还应确认 zh-CN/SteamWrapper.Application.resources.dll 存在。ResourceManager 指定语言查找

品牌资源由 assets/brand/steamwrapper.svg 统一生成。修改该源文件后运行 pnpm brand:generate,再用 pnpm brand:check 检查 SVG、PNG、ICO 及随包副本是否一致;不要分别手工修改导出图标。

工具链诊断与组合质量检查:

终端窗口
pwsh -NoProfile -File scripts/windows/Invoke-Build.ps1 -Action Doctor # 工具版本、link/cl 和 SDK 路径
pwsh -NoProfile -File scripts/windows/Invoke-Build.ps1 -Action RustTest # 当前 Rust workspace 测试
pwsh -NoProfile -File scripts/windows/Invoke-Build.ps1 -Action Verify # Rust 格式/check/测试、C# 测试、契约和 WinUI 发布,遇错即停
pwsh -NoProfile -File scripts/windows/Test-WinUIBuild.ps1 # 独立 XAML 项目的自包含目录发布验证

Invoke-Build.ps1 -Action Verify 依次运行 cargo fmt --all -- --check、cargo check --locked --workspace、cargo test --locked --workspace,再运行 Invoke-WinUI.ps1 -Action Test、Test-WinUIContracts.ps1 和 Invoke-WinUI.ps1 -Action Publish。它不运行原生 UI 套件、不创建 GitHub Release 或安装器,也不操作真实 Steam。可选 just 配方调用同一套 Rust/WinUI 命令;文档和品牌验证使用各自的 pnpm 命令。

一次性工具调用可用:

终端窗口
dotnet --version
cargo test --locked -p steamwrapper-runner

如果在 Windows 上使用 mise 进行一次性调用,可执行 mise.exe exec -- dotnet --version(Cargo 命令同理)。本机曾观察到 PowerShell 激活函数会吞掉 exec 的裸 -- 分隔符;mise run ... 不受影响。上面的直接命令不经过该包装,也没有为此修改用户 PowerShell 配置。

共享数据路径与真实 Steam 验收

章节“共享数据路径与真实 Steam 验收”

Manager 和 Steam 启动的 Runner 必须看到同一份 %LOCALAPPDATA%\SteamWrapper\profiles.toml 与 bin\SteamWrapperRunner.exe。本机发现:从 Codex 的进程环境启动 shell 或 Manager 时,字面上的常规 AppData 路径可以落到 Codex 包的 LocalCache 私有目录;文件存在、摘要匹配、直接运行成功都不足以证明普通 Steam 可访问它。shell 或 Manager 报告没有 package identity,也不能否认这种文件视图差异。此次差异由文件句柄的最终路径确认。

共享文件位置检查在判定 Runner 就绪前核验现有 Runner 与存在的 profile,并在复制安装候选前、安装完成时核验对应文件。句柄最终路径与解析显式 junction/symlink 后的逻辑路径不符时,服务返回非就绪并提示从资源管理器重新打开 Manager;配置编辑算法和 Launch Options 格式不变。比较接受合法链接、大小写差异及 \\?\ / UNC 前缀;缺少 profile 不影响独立 Runner 健康检查。此检查证明共享位置一致性,不替代真实 Steam 启动验收。

有用户授权后,真实验收按普通玩家的启动方式执行:

  1. 记录所选游戏原启动项,准备文件完整性基线和存档保护;存在未解决的云同步冲突时停止。
  2. 关闭 Manager,在正常 Windows 资源管理器地址栏打开本仓库 target\winui\publish 的完整目录,再双击 SteamWrapper.Manager.exe。保留完整发布目录;从 Codex shell 调用进程启动 API 不能作为已经脱离其文件视图的证据。
  3. 在该 Manager 中完成配置与稳定 Runner 安装,确认没有共享位置警告。复制既有格式的启动项到 Steam,关闭 Manager,再从 Steam 启动所选游戏;分别记录 Runner/游戏进程、标题界面、退出后 Steam 状态与显示时长。
  4. 测试结束恢复原启动项,复查游戏文件与原存档。UI 回到“开始”或云显示最新,不能代替文件完整性核对。

日常开发使用上面的直接脚本和沙盒命令,或它们的可选 mise 别名。通过本机普通 Explorer 的一次真实游戏验收,不等于干净 Windows VM、安装器、覆盖更新或卸载验收。

官方 CLI 模板能够通过 .NET 创建 WinUI/XAML 项目。0.0.6-alpha 的创建后操作会无条件更新三个 NuGet 包,UseLatestWindowsAppSDK=false 未约束这些操作;脚本在生成后用 XML 固定实际包引用和最低系统版本,再发布。不能只凭模板参数宣称版本已经固定。WinUI 官方快速入门

原生 UI 工具提供首个可重复的 WinUI 回归切片,更广验收仍在路线图中。它引用 Windows 自动化/WPF API 作为开发工具,不是随产品交付的 UI 实现。C# 服务、契约、发布及工具编译不能替代实际交互执行,也不覆盖其余选择器、键盘/输入法、语言、缩放与玩家检查。本地隔离执行不等于干净 Windows 安装。

smoke 使用 net10.0-windows10.0.26100.0、x64、unpackaged、.NET/Windows App SDK self-contained,暂不启用 trimming。它验证 XAML 编译与发布目录,不安装/启动 MSIX、不启用 Developer Mode、不启动游戏,也不证明干净系统运行或原生交互已经验收。实际 Manager 已建立独立项目、包锁定、服务和跨语言测试。

本机安装与验证记录

章节“本机安装与验证记录”

2026-09-07–09-08 归档证据。 以下结果描述当轮实现和工具组合,包括如今已移除的 Dioxus app 与 manager-core;不是当前命令或最新提交结果。旧源码、脚本和工作流固定在 ca6a09e。Dioxus Native E2E 不验证 WinUI;WinUI 服务/发布和真实游戏记录各自保留原有范围。

2026-09-07:当轮 mise 工具已安装。Build Tools 注册版本为 18.9.12112.369,检测到 MSVC 14.51.36231 和 Windows SDK 10.0.26100.0。安装器返回过 3010;用户随后完成重启。本轮复检 .NET、MSVC、SDK 与项目工具可用。

当轮已完成的本机验证:

验证 结果
mise install、组件安装任务重复执行、windows:doctor 通过;已安装项不会重复覆盖,当前开发 shell 可用
WinUI 固定依赖后的自包含发布 通过;目录包含非空 EXE、coreclr.dll 和 Microsoft.UI.Xaml.dll;未启用裁剪
Manager 组件精简后的 fresh publish 通过;171.196 MiB / 179,511,987 字节 / 457 文件,旧 AI/ML 等依赖无残留,Runner 清单摘要匹配
Test-WinUIPublish.ps1 5 项通过;先复现旧发布保留哨兵的失败,再验证新发布与错误恢复
共享数据位置保护的 winui:test / winui:contracts 43/43 C# 用例通过,其中 9 条新增位置回归;Runner 与 profile 重定向先复现失败再修复,原生句柄与真实 junction 正例通过;跨语言及受控 Runner 契约通过
cargo fmt --all -- --check、cargo check --locked --workspace 通过
cargo test --locked --workspace 全部通过,包括 Windows Runner 的 6 项测试
冻结 pnpm 安装、E2E TypeScript 检查 通过
dx check、dx build --release、release Runner staging 通过;Dioxus 产物在 target/dx/SteamWrapperManager/release/windows/app
Cargo e2e feature 构建、隔离 Native E2E 通过,3 个 spec / 6 个用例
mise 任务校验、PowerShell AST、JSON/TOML 版本一致性、文档链接和 diff 通过

安装后验证复现并修正了三个现有 Windows 工具/测试问题:Manager service 测试硬编码 Linux wait mode、Native E2E 直接启动 pnpm.cmd 的 EINVAL、Runner 路径断言硬编码 /。pnpm 也明确禁用了当时 embedded provider 不使用的 Edge/Gecko 下载脚本,保留 esbuild。没有修改产品运行逻辑或降低现有断言要求。

完整验证任务最初遇错停止;最后的路径断言修正后,仅重跑受影响的 TypeScript 和 E2E,其余已通过检查未重复。日志保留在忽略的 target/windows-verify.log、target/windows-runner-test.log、target/windows-e2e.log 和 target/winui-toolchain-build.log。

后续实现已通过 C# 配置/服务测试和 winui:contracts:C# 单字段编辑由 Rust 全量比较语义,真实 Runner 验证中文路径、精确 argv/cwd、job/root 等待差别、退出码与缺失目标日志。证据位于忽略的 target/winui-contracts/;原生预览记录见 首个切片验收。这些 fixture 结果本身不代表新安装器、干净系统运行或真实 Steam 时长验收;真实游戏结果单独记录如下。

后续补齐 Native E2E 启动失败日志后,本机 Windows 再次通过 3 个 spec / 6 项测试,退出码 0 且无 Manager 残留;日志为 target/native-e2e-wrapper-1f429cd320e1437f98e8be2331c68c0f/native-e2e.log。

用户授权的真实 galgame The NOexistenceN of you AND me(AppID 2873080)已完成本机 Steam 闭环:2026-09-07 12:46:03 从 Steam 启动 Runner 和游戏,标题界面正常退出后,Steam 在 12:53:33 记录 Runner、游戏与 Unity 子进程全部 exit 0;UI 回到“开始”、云显示最新,累计时长显示从 11.2 变为 11.4 小时,原空启动项已恢复。此前 OS Error 3 对应的是 Codex 私有 AppData 文件视图;通过正常 Explorer 打开同一 Manager、在真实稳定目录安装后,原启动项格式未作修改即成功。最终 35/35 个游戏文件与 4/4 份原存档的 SHA-256 均与初始基线一致;存档句柄最终路径也确认未被重定向。详见 真实 Steam 验证。

新增位置保护的发布产物已完成两种启动上下文的原生复核:从受重定向的工具环境打开时显示位置警告,保存后不显示启动项或复制按钮;从普通 Explorer 打开新版 Manager(PID 13644,父进程 11316 为 explorer.exe)后保存成功,生成完全一致的既有命令格式。这是本机窗口与共享路径证据,干净 Windows VM、安装器和卸载边界仍未验收。

组件精简与发布保护的证据在 target/winui-component-study/integrated-publish.json、publish-regression-before.log 和 publish-regression-after.log。此次已验证构建、布局与发布恢复;精简后最终产物另行通过沙盒原生窗口、配置读取、picker 打开/取消、保存和稳定 Runner 就绪复核。旧 226.23 MiB 产物的 6 轮启动/内存数据没有作为新产物复测结果,干净 Windows 系统也尚未测试。Windows CI 在上传预览前运行 Test-WinUIPublish.ps1,同时完成发布与 5 项发布回归。

提交 3d322db 的 WinUI CI与 v2 完整门禁均已通过。后者包含 Windows/Ubuntu Native E2E、各平台 Runner 独立进程测试及 Linux AppImage 构建、实际解包检查和上传。远程运行中发现的 Linux libxdo 缺失、Native E2E 无显示环境、AppImage 解包校验相对路径问题已修复并经新提交完整运行确认;未降低门禁要求。CNB 同步成功。以上记录对应代码提交,不将后续仅文档提交的运行状态提前写为通过。

2026-09-08 界面语言实现通过最终 mise run winui:test,共 59/59 项,其中新增 10 项本地化/偏好测试。默认英语回归先在旧中文消息上观察失败,UTF-8 BOM 偏好读取和嵌套 JSON 重复键拒绝也先失败再修复。覆盖双语资源键与格式参数、嵌套服务消息切换、诊断/用户数据不变、规范语言落盘、未知 JSON 字段、损坏/重复/过大设置及 BOM 输入。跨语言/Runner 契约和最终自包含发布通过,包含 zh-CN 卫星资源。后续语言验收记录一次性 fixture 中的最终原生切换、重启保持、输入/profile 字节保留和应用/窗口图标检查;这些不替代干净系统或真实 Steam 验收。