PowerToys Advanced Paste:AI 粘贴预览机制与稀疏包身份调试实战指南
【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys
本文基于 PowerToys 官方开发文档 advancedpaste.md,系统讲解 Advanced Paste 模块的两个核心技术点:其"AI 粘贴预览"功能的实现流程(ShowCustomPreview设置如何复用已生成的 AI 响应而不消耗额外调用),以及作为非打包 WinUI 3 应用的PowerToys.AdvancedPaste.exe如何通过共享稀疏 MSIX 包(Microsoft.PowerToys.SparseApp)获得包身份以解锁 Windows AI 受限功能(Phi Silica /LanguageModel)。读完后你将掌握本地调试 Advanced Paste 的完整流程、稀疏包一键注册与验证命令、常见故障的定位方法,以及 Settings UI 通过子进程探测 AI 可用性的机制。
模块概览
Advanced Paste 是 PowerToys 中提供"增强剪贴板粘贴"的模块:在标准粘贴之外,提供带格式化选项与 AI 处理能力的粘贴动作(如修正拼写与语法、自定义 AI 粘贴等)。源码位于 src/modules/AdvancedPaste,核心 C# 项目在 src/modules/AdvancedPaste/AdvancedPaste,模块接口层(负责进程管理与命名管道 IPC)位于 src/modules/AdvancedPaste/AdvancedPasteModuleInterface。
从源码结构看,该模块是一个非打包(unpackaged)、自包含的 WinUI 3 应用PowerToys.AdvancedPaste.exe。要调用 Phi Silica 的Microsoft.Windows.AI.Text.LanguageModelAPI,进程必须具备匹配的包身份——这正是后文稀疏包身份机制要解决的问题。模块入口在 Program.cs,其中还能看到 GPO 策略检查(管理员可通过组策略禁用该工具)、AppInstance.FindOrRegisterForKey单实例保护等启动逻辑。
AI 粘贴预览:ShowCustomPreview与生成结果缓存
官方文档中最关键的实现说明是:"Show preview" 设置(ShowCustomPreview)控制 AI 生成结果是否在粘贴前于预览窗口中展示,且预览功能不额外消耗 AI 调用额度——预览展示的是同一次 API 调用已经生成、并在本地缓存的结果。
文档给出的实现流程为:
- 用户发起 "Paste with AI" 动作;
- 通过
ExecutePasteFormatAsync发起单次AI API 调用; - 结果缓存在
GeneratedResponses集合中; - 若预览已启用,缓存结果展示在预览 UI 中;
- 用户粘贴缓存结果时不再产生任何额外 API 调用。
这一流程在源码中可以得到逐条印证。核心方法ExecutePasteFormatAsync(PasteFormat, PasteActionSource)位于 OptionsViewModel.cs:
- 第 746 行调用
_pasteFormatExecutor.ExecutePasteFormatAsync(...)执行实际的格式转换(对 AI 动作即一次 AI 调用),执行器接口见 IPasteFormatExecutor.cs 与实现 PasteFormatExecutor.cs; - 第 753 行是预览判定条件:
pasteFormat.Metadata.CanPreview && _userSettings.ShowCustomPreview && !string.IsNullOrEmpty(outputText) && source != PasteActionSource.GlobalKeyboardShortcut——即格式元数据允许预览、用户开启ShowCustomPreview、输出非空、且来源不是全局快捷键时才走预览;"拼写/语法修正"的引导(coaching)模式则会强制预览; - 第 763 行
GeneratedResponses.Add(outputText)将结果写入ObservableCollection<string> GeneratedResponses(定义于第 583 行),并更新CurrentResponseIndex指向最新一条,随后触发PreviewRequested事件展示预览界面。
也就是说,AI 调用只发生一次,预览与最终粘贴消费的都是同一个dataPackage/ 缓存文本,这与文档中"预览不消耗额外 AI 额度"的结论一致。
设置项
| 设置 | 说明 |
|---|---|
ShowCustomPreview | 启用后,粘贴前在预览窗口中展示 AI 生成的结果。不影响 AI 额度消耗。 |
ShowCustomPreview作为用户设置字段在 UserSettings.cs 中定义,模块接口层(dllmain.cpp)也引用了该字段进行设置序列化。
调试:运行与附加调试器
由于 Advanced Paste 由 Runner 在模块启用后于后台拉起,官方文档给出的标准调试步骤是:
- 在 Visual Studio 中将Runner项目(src/runner)设为启动项目;
- 启动 Runner(F5),拉起 PowerToys 托盘图标并加载所有模块接口;
- 打开设置(右键托盘图标 → Settings),确认已启用Advanced Paste模块。启用后模块会立即在后台启动
PowerToys.AdvancedPaste.exe; - 在 Visual Studio 中选择Debug → Attach to Process(
Ctrl+Alt+P),附加到PowerToys.AdvancedPaste.exe,调试器类型选择Managed (.NET Core)。
替代方案:使用 VS Code 的启动配置"Run AdvancedPaste"(位于 .vscode/launch.json)直接拉起 exe——但文档明确提示:没有 Runner 时,IPC 与全局快捷键均不可用,因为管道服务器与快捷键注册都由模块接口层(Runner 进程内)负责。
稀疏包身份:非打包 WinUI 3 应用的包身份问题
为什么需要稀疏包身份
LanguageModelAPI 需要 Limited Access Feature(LAF)解锁,而解锁只有调用进程具备匹配包身份时才会成功;- Advanced Paste 是非打包、自包含的 WinUI 3 应用。稀疏包在不将其转换为完整 MSIX的前提下授予其身份;
- csproj 使用
<ProjectPriFileName>PowerToys.AdvancedPaste.pri</ProjectPriFileName>(与 ImageResizer 等其他 WinUI3 应用相同的自定义 PRI 命名约定)。这一点可在 AdvancedPaste.csproj 第 24 行确认。该约定要求 WindowsAppSDK Foundation ≥ 2.0.22(对应 WindowsAppSDK 的 PR #6376),该版本修复了 MRT 在稀疏身份下查找自定义命名 PRI 文件的问题,使Application.LoadComponent能解析自定义 PRI 名而不是硬编码resources.pri。
一键开发环境搭建
完整的稀疏包文档位于 src/PackageIdentity/readme.md。Advanced Paste 文档给出的一键开发注册命令为:
pwsh src/PackageIdentity/BuildSparsePackage.ps1 -Platform ARM64 -Configuration Debug -DevRegister-DevRegister的行为(对应脚本 BuildSparsePackage.ps1):
- 在
src/PackageIdentity/.user/下生成开发证书(仅首次运行); - 自动将该证书导入
CurrentUser\TrustedPeople与CurrentUser\Root,使系统愿意把稀疏身份授予 AP(没有信任关系时,GetPackageFamilyName会返回APPMODEL_ERROR_NO_PACKAGE,LAF 解锁静默失败); - 移除此前的注册;
- 在
AppxManifest.xml的临时副本中重写 publisher,使其匹配开发证书主题; - 通过
Add-AppxPackage -Register … -ExternalLocation X:\…\<Platform>\<Config>\WinUI3Apps完成注册。
关于
-ExternalLocation指向WinUI3Apps子目录的原因,src/PackageIdentity/readme.md 有进一步说明:MSIX 本身只含元数据,将其指向 Win32 可执行文件所在子目录,可以把 MSIX 注册在 Windows 23H2/24H2 上引发的 DACL 变更隔离在WinUI3Apps文件夹内,保持安装根目录干净(预览处理器 DLL 仍从根目录加载)。
BuildSparsePackage.ps1还支持的其他开关:
-Clean:清理此前bin/obj输出并卸载已有安装;-ForceCert:重新生成本地开发证书(.pfx/.cer/.pwd/.thumbprint);-NoSign:跳过签名(MSIX 仍能构建,但部署前必须签名);-CIBuild(或$env:CIBuild = 'true'):保留 manifest 中的 publisher 原样、跳过本地证书替换,供 CI 使用。
注册后验证
$pkg = Get-AppxPackage -Name '*SparseApp*' $pkg.PackageFamilyName # Microsoft.PowerToys.SparseApp_<PublisherId> $pkg.PublisherId $pkg.IsDevelopmentMode # True然后确认 AP 在运行时确实获得了稀疏身份:
& 'ARM64\Debug\WinUI3Apps\PowerToys.AdvancedPaste.exe' --check-phi-silica # Exit 0 = Available, 1 = NotReady, 2 = NotSupported重新构建 AP、修改 AppxManifest.xml 或切换平台/配置后,需重新运行同一命令以完成重新注册;使用-Unregister可注销身份。此外,打包完成后脚本还会输出src/PackageIdentity/.user/PowerToysSparse.publisher.txt,镜像注册后 Windows 可见的 publisher 字符串,供其他组件在生成自身 manifest 时保持同步。
故障排查表
官方文档给出的排查表(完整继承):
| 问题 | 原因 | 解决方案 |
|---|---|---|
运行时GetPackageFamilyName返回APPMODEL_ERROR_NO_PACKAGE(15700),LAF 解锁返回Unavailable | 开发证书未被信任(或稀疏包未注册) | 重新运行BuildSparsePackage.ps1 -DevRegister——会自动把证书导入TrustedPeople与Root。 |
AP 或 Settings 启动时Microsoft.UI.Xaml.dll崩溃,错误0xC000027B(class-not-registered) | AppxManifest.xml中<Application>的Executable路径无法在已注册的ExternalLocation(<Config>\WinUI3Apps\)下解析 | 确认每个Executable相对于WinUI3Apps\(见 issue #47177),且文件存在于构建输出中。 |
| 通过快捷键触发时 AP 启动但始终不显示窗口 | Runner 的管道服务器等待在 AP 冷启动完成 WinAppSDK + DI 宿主引导之前超时 | AdvancedPasteProcessManager.cpp中 15 秒管道超时已缓解该问题;热启动连接远低于 1 秒。对应源码见 AdvancedPasteProcessManager.cpp |
XamlParseException/ 找不到ms-appx:///Microsoft.UI.Xaml/Themes/… | WindowsAppSDK Foundation < 2.0.22;MRT 无法在稀疏身份下解析自定义 PRI 名 | 确保Directory.Packages.props中Microsoft.WindowsAppSDK.Foundation≥ 2.0.22。 |
Settings UI 如何检查 Phi Silica 可用性
Settings UI 本身没有稀疏包身份,无法直接探测 Phi Silica。它的做法是把 Advanced Paste 作为短命子进程启动:
PowerToys.AdvancedPaste.exe --check-phi-silicaProgram.cs 中Program.Main识别该参数并进入CheckPhiSilicaAvailability():先调用PhiSilicaLafHelper.TryUnlock(),再调用LanguageModel.GetReadyState(),向 stdout 输出Available/NotReady/NotSupported之一,并以相应退出码结束(0 = Available,1 = NotReady,2 = NotSupported 或错误)。Settings 端读取 stdout 并等待最多 10 秒。由于每次检查都是全新进程,瞬时的Unavailable结果不会跨检查缓存。
LAF 解锁逻辑在 PhiSilicaLafHelper.cs 中:特性 ID 为com.microsoft.windows.ai.languagemodel,只缓存成功的解锁结果——失败(Unavailable、未知状态、异常)往往是瞬时的(例如登录前 AI 特性栈尚未初始化、或稀疏身份尚未完全应用到刚启动的进程),下次调用时重试即可恢复。LastUnlockStatus属性暴露最近一次解锁状态,便于诊断真实的 LAF 结果,而不是下游模型调用那句笼统的 "Access is denied"。
源码中还有一个文档未展开的兄弟参数--prepare-phi-silica(Program.cs):它在不启动 WinUI 应用的情况下触发 Phi Silica 模型准备(下载),通过EnsureReadyAsync()把模型从NotReady推进到Ready,退出码为 0 = ready、1 = 准备失败、2 = 不受支持。注释还说明了一个细节:EnsureReadyAsync这类 WinRT 异步操作若从[STAThread]入口点阻塞等待无法正确编组,因此代码将其放到线程池线程上执行。
延伸资料
- advancedpaste-phisilica-local-testing.md:Phi Silica 可用性的分层诊断与本地测试/故障排查指南;
- src/PackageIdentity/readme.md:稀疏包的完整文档,包括构建、签名、注册/注销、CI 指引,以及"其他组件如何消费稀疏身份"的六步流程(在
AppxManifest.xml中新增<Application>条目、在 Win32 二进制中嵌入带<msix>元素的 sparse identity manifest、使用shell:AppsFolder\...激活形式启动等); - Advanced Paste 的设置界面与 DSC 资源分别见 Settings UI 与 doc/dsc/modules/AdvancedPaste.md 中的说明。
适用前提与限制:上述调试与稀疏包注册流程面向 Windows 本地开发环境(PowerShell + Visual Studio / VS Code),--check-phi-silica的可用性结果取决于系统 AI 特性栈、硬件与授权状态;Phi Silica 相关 API 仅在有 Windows AI 能力的系统上返回Ready,其他系统会以NotReady或NotSupported状态呈现,属预期行为。
【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考