WinUI 构建与运行常见错误排查手册:microsoft-ui-xaml 实战指南
【免费下载链接】microsoft-ui-xamlWinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.项目地址: https://gitcode.com/GitHub_Trending/mi/microsoft-ui-xaml
本文基于 microsoft-ui-xaml 仓库的官方 FAQ(docs/common-errors-FAQ.md),系统梳理在搭建 WinUI 开发环境、编译产品代码与测试工程、构建 WinUI Gallery 以及处理 T4 模板文件异常时的典型报错。读完后,你将掌握 NuGet 凭据错误的修复方式、恢复构建"干净状态"的标准命令组合、build.cmd关键开关的底层行为、mock 包缓存冲突与 NU1102/NU1603 版本问题的处理路径,以及用调试器定位 stowed exceptions 崩溃的技巧。
一、搭建开发环境时的 NuGet 凭据错误
在初始化构建环境或执行 NuGet 还原时,可能遇到CredentialsProvider相关的凭据插件异常:
`CredentialProvider.Microsoft' due to an unrecoverable fault: NuGet.Protocol.Plugins.ProtocolException: A plugin protocol exception occurred. ---> NuGet.Protocol.Plugins.ProtocolException: The parameter is incorrect.或者 401 未授权错误:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets(128,5): error : Response status code does not indicate success: 401 (Unauthorized).这两类错误本质上是本地缓存的 NuGet 凭据会话失效导致的。FAQ 给出了两种处理方案:
- 强制重新认证:按照 NuGet 跨平台认证插件的官方文档执行强制重新认证(
nuget login/nuget logout类操作); - 删除凭据缓存文件:直接删除
C:\Users\<user>\AppData\Local\MicrosoftCredentialProvider\SessionTokenCache.dat,该文件会强制下一次访问时重新走认证流程。
需要说明的是,本仓库的 NuGet.config 将包源固定为内部 Azure DevOps 制品库(WinUI.Dependencies源)加上本地的 PackageStore 目录,且通过globalPackagesFolder/repositoryPath把全局缓存重定向到仓库外一级的packages目录。凭据失效时,访问这些源就会触发上述 401 错误,因此重新认证是针对包源访问层的问题,而不是代码问题。
二、构建 WinUI:恢复"干净状态"的标准流程
一条成功的构建允许出现警告,但错误数必须为 0。FAQ 给出的通用排错准则是:当构建出现莫名其妙的错误时,按顺序执行以下命令,把本地环境恢复到干净状态:
git clean -xdf nuget locals all -clear tools\clean.cmd这三条命令在仓库中的实际行为如下,可以对照确认它们各自清掉了什么:
git clean -xdf删除所有未被 Git 跟踪的文件与目录(含忽略文件),保证工作树与仓库提交一致;nuget locals all -clear清空本机所有 NuGet 缓存;- tools/clean.cmd 会先强制结束
msbuild.exe与VBCSCompiler.exe进程(它们会持有输出目录中的文件句柄,导致删除失败),然后删除BuildOutput下的bin、obj、temp、packaging子目录,以及WindowsAppSDK(mock 包输出)和TestPayload目录。它支持两个开关:/all表示删除所有架构的输出,/packages表示连packages、src\packages、src\XamlCompiler\packages以及PackageStore一并清掉——使用/packages之后必须重新运行init.cmd恢复包。
2.1 堆内存不足时:用/b开关降并发
如果构建过程中出现 out-of-heap(内存耗尽)错误,应使用build.cmd的/b开关。从 Build.cmd 源码可以看到,默认并发数是/m:4(注释说明 4 个 MSBuild 实例是"构建速度与内存安全之间的合理平衡"),而/b开关将_procCount改写为/m:2(Build.cmd),即"后台"构建,只启动 2 个msbuild.exe实例,从而压低峰值内存。反之,/m会按 CPU 核心数拉满并发,构建更快但更容易 OOM,且不能与/b混用(Build.cmd)。
顺带说明build.cmd /c的完整语义:它会先调用clean.cmd /all全量清理,再自动追加/restore(Build.cmd),所以"清理 + 还原 + 构建"一步到位。
2.2 WindowsAppSdkMockCheck 错误:mock 包进入了全局缓存
构建时如果看到如下错误:
C:\.tools\.nuget\packages\microsoft.windowsappsdk\999.0.0-mock-3.0.0-dev-x64-release\buildTransitive\Microsoft.WindowsAppSDK.Custom.targets(12,5): The Windows App SDK mock package should not be installed into a shared/global cache. If this was intended, set WindowsAppSdkMockCheck=false in your project to suppress this error. If this was not intended, delete the mock package from your shared/global cache, use a nuget.config with globalPackagesFolder and/or repositoryPath set to a custom location, and avoid using the NUGET_PACKAGES environment variable.原因是 mock 版本的 Windows App SDK 包(由 Build.cmd 中的pack.component.cmd /version 3.0.0-dev打包产生)本应只落在仓库私有的包目录里,却出现在了共享/全局 NuGet 缓存中。错误信息本身给出了三条路:在项目中设置WindowsAppSdkMockCheck=false抑制检查、从全局缓存中删除该 mock 包,或使用设置了globalPackagesFolder/repositoryPath的 nuget.config 并把NUGET_PACKAGES环境变量排除在外。
FAQ 推荐的直接做法是:从系统环境变量中删除NUGET_PACKAGES,打开一个新的命令行窗口,重新构建。NUGET_PACKAGES会覆盖 nuget.config 中的globalPackagesFolder设定,使包还原到用户全局缓存(%USERPROFILE%\.nuget\packages),这正是 mock 包"泄漏"到共享缓存的常见途径。本仓库的 NuGet.config 已经配置了自定义的globalPackagesFolder,只有当NUGET_PACKAGES存在时该配置才会被旁路。
另一种触发场景:构建成功后在 Visual Studio 中启动 MUXControlsTestApp,运行时再次出现同样的WindowsAppSdkMockCheck错误。此时 FAQ 的处理方式是:关闭解决方案,改用buildsamples.cmd重新构建,构建成功后再次启动 MuxControlsTestApp。查看 buildsamples.cmd 源码可知,它会依次构建全部示例工程(C# Desktop、C++ Desktop、Island、DisableXamlGeneratedMain、WinUIGallery、ChartApp、TableView 等),并对每个工程显式带上/restore;C++ Desktop 工程特意不使用/m并行,因为.wapproj的附加属性会导致同一项目被两个 MSBuild 进程同时构建。
2.3 NU1102:package store 中找不到指定版本
如果看到"找不到包版本"类错误,例如:
D:\xaml\controls\test\MUXControls.Test\MUXControls.Test.csproj : error NU1102: Unable to find package Microsoft.NETCore.App.Crossgen2.win-x64 with version (= 8.0.21) [D:\xaml\controls\MUXControls.sln] D:\xaml\controls\test\MUXControls.Test\MUXControls.Test.csproj : error NU1102: - Found 65 version(s) in WinUI.Dependencies [ Nearest version: 8.0.20 ] [D:\xaml\controls\MUXControls.sln] D:\xaml\controls\test\MUXControls.Test\MUXControls.Test.csproj : error NU1102: - Found 0 version(s) in packagestore [D:\xaml\controls\MUXControls.sln]注意错误详情中列出了两个源的查找结果:WinUI.Dependencies(远程内部源)找到了 65 个版本但最近的是 8.0.20,本地packagestore则为 0。这表示内部制品库尚未推送所需的 8.0.21 版本。FAQ 的处置建议是:为此提交一个 issue,让内部 feed 更新到所需版本。
与之伴随出现的警告:
D:\xaml\controls\test\MUXControlsTestApp\MUXControlsTestApp.csproj : warning NU1603: MUXControlsTestApp depends on Microsoft.NET.ILLink.Tasks (>= 8.0.21) but Microsoft.NET.ILLink.Tasks 8.0.21 was not found. Microsoft.NET.ILLink.Tasks 9.0.4 was resolved instead.NU1603 说明 NuGet 把依赖浮动到了 9.0.4,会造成版本不一致。待内部 feed 补齐版本后,FAQ 建议执行一次干净构建:
build.cmd /c结合前文对/c的源码分析,这条命令实际执行"全量清理 + 强制还原 + 重新构建",是消除版本漂移的标准动作。
三、构建 WinUI Gallery 的常见问题
3.1 NuGet 依赖缺失:先 restore 再构建
如果 Gallery 构建因缺失 NuGet 依赖而失败,FAQ 建议直接对解决方案执行:
nuget restore WinUIGallery.slnx(WinUIGallery.slnx为实际解决方案文件名,buildsamples.cmd 中同样以该名称引用Samples\WinUIGallery\WinUIGallery.slnx,且 Release 配置下会追加/p:PublishAot=true。)
3.2 Stowed Exceptions 崩溃:在 CaptureErrorContext 打断点
运行期如果崩溃且调用栈顶部是Microsoft_UI_Xaml!FailFastWithStowedExceptions,说明 XAML 框架把一个被"扣留"(stowed)的异常在延迟处理点转成了 FailFast。FAQ 给出的技巧是:在 dxaml/xcp/components/base/errorcontext.cpp 的CaptureErrorContext中设置断点,该函数会在捕获错误上下文时记录真实的失败 HRESULT 与调用帧信息,从而看到崩溃的根因而不是 FailFast 表象。
从源码结构看,CaptureErrorContext(HRESULT failedFrameHR, INSTRUCTION_ADDRESS callerReturnAddress, CONTEXT* contextRecord, ...)声明于 errorcontext.h,其实现接收失败帧的 HRESULT、调用方返回地址与上下文记录,把"哪个 API、在哪一行、什么错误码"组合进错误上下文;FailFastWithStowedExceptions(errorcontext.cpp)则是在处理 stowed 异常时最终触发进程终止的路径。因此断点打在CaptureErrorContext上,正是拦截"真实错误信息"的时机。
四、"Modified" 的 T4 (.tt) 文件实际没有内容变化
Git 检出时,某些 T4 模板文件(如group.tt这类)中的制表符可能被转换成空格,但 Git 在比对时认为两者等价,因此git checkout --、restore 或 hard reset 都无法把它们还原回未修改状态,导致git status中长期挂着"已修改"的文件。本仓库中的 T4 模板集中在 src/XamlCompiler/BuildTasks/Microsoft/Xaml/XamlCompiler/CodeGenerators 等目录,是 XAML 编译器代码生成的源头文件,这类伪修改状态在检出新分支后尤其常见。
FAQ 给出的解法是重写索引并强制重置:
注意:运行以下命令前,不要有任何未提交的更改——所有未提交更改都会被覆盖。
git rm -r --cached . git reset --hard HEAD原理是:git rm -r --cached .把所有文件从暂存区(索引)移除但不触碰工作区文件,随后git reset --hard HEAD重建索引并以 HEAD 提交为准重写工作区文件,从而让 Git 用提交中的原始字节(含原始制表符)覆盖掉被换行符/空格转换污染的工作区副本。执行前务必确认git status干净,或先把本地改动提交/暂存。
五、小结:一张排错决策表
| 现象 | 定位 | 处置 |
|---|---|---|
CredentialProvider异常 / 401 Unauthorized | NuGet 凭据会话失效 | 强制重新认证,或删除SessionTokenCache.dat |
| 构建报 OOM / out-of-heap | MSBuild 并发过高 | build.cmd /b(/m:2后台模式) |
WindowsAppSdkMockCheck错误 | mock 包落入全局 NuGet 缓存 | 删除NUGET_PACKAGES环境变量,新开命令行重构建;VS 内启动报同样错误时改用buildsamples.cmd重建 |
| NU1102 找不到指定版本包 | 内部 feed 缺版本 | 提 issue 等 feed 更新,随后build.cmd /c干净重建 |
| Gallery 构建缺 NuGet 依赖 | 解决方案未还原 | nuget restore WinUIGallery.slnx |
FailFastWithStowedExceptions崩溃 | stowed 异常延迟 FailFast | 在 errorcontext.cpp 的CaptureErrorContext打断点取真实错误 |
| T4 (.tt) 文件无实质修改却显示 Modified | 检出时制表符被转为空格 | 无未提交更改时执行git rm -r --cached .+git reset --hard HEAD |
以上所有命令与文件均针对当前仓库的实际结构:入口构建脚本为 Build.cmd,清理脚本为 tools/clean.cmd,示例工程构建入口为 buildsamples.cmd,包源与缓存策略见 NuGet.config。建议将这些脚本与本文对照阅读,即可在本地独立完成 WinUI 的构建、示例编译与常见故障恢复。
【免费下载链接】microsoft-ui-xamlWinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.项目地址: https://gitcode.com/GitHub_Trending/mi/microsoft-ui-xaml
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考