许多Windows API(推送通知、后台任务、共享目标、启动任务、Windows AI API)要求应用具有打包标识。 在开发过程中,你不希望每次测试时生成完整的 MSIX 安装程序 , winapp 会提供两个命令,以便实时提供应用标识。
将Visual Studio用于打包项目? 如果已对打包项目使用Visual Studio,则可能不需要 winapp 进行调试。 Visual Studio 已处理包注册、标识、AUMID 激活、调试器挂载和激活代码调试——所有操作均通过按下 F5 触发。 它还为高级方案提供 调试→其他调试目标→调试已安装的应用包 。 下面的工作流最适用于 VS Code 用户、基于终端的工作流和 VS 不本机打包的框架 (Rust、Flutter、Tauri、Electron、plain C++)。
两种方法: winapp run 与 create-debug-identity
winapp run |
create-debug-identity |
|
|---|---|---|
| 它所注册的内容 | 完整松散布局包(整个文件夹) | 稀疏包 (单一可执行文件) |
| 应用启动方式 | 由 winapp 启动(用于激活或执行的 AUMID 别名) | 您自行启动可执行文件(通过命令行、集成开发环境等) |
| 模拟 MSIX 安装 | 是 — 最接近生产行为 | 否 - 仅稀疏标识 |
| 文件保持原位 | 复制到 AppX 布局目录 | 是 — exe 停留在其原始路径上 |
| 身份范围 | 整个文件夹内容(exe、DLL、assets) | 单个可执行文件 |
| 调试器友好 | 在启动后附加到 PID,或使用 --no-launch 然后通过别名启动 |
IDE 调试器直接运行 — exe 文件始终具有标识 |
| 控制台应用支持 |
--with-alias 在终端中保留 stdin/stdout |
直接在终端中运行 exe |
| 最适用于 | 大多数框架(.NET、C++、Rust、Flutter、Tauri) | Electron,或者当您需要完整的 IDE 调试器控制(F5)时 |
何时使用哪一个
默认值:winapp run
使用winapp run进行大多数开发工作流。 它模拟实际的 MSIX 安装 — 你的应用获取在生产环境中相同的标识、功能和文件关联。
# Build your app, then:
winapp run .\build\output
在以下情况下使用 create-debug-identity:
-
你的可执行文件(exe)与生成产物分离——例如,Electron 应用程序,其中
electron.exe位于node_modules/ - 你需要调试启动代码 ,并且无法在 AUMID 启动后快速附加调试器
-
对于某些无法通过 AUMID 启动的调试器来说,需要为启动的进程提供标识来注册 exe ,
create-debug-identity这样无论它如何启动,都具有标识。 - 你正在专门测试稀疏包行为(AllowExternalContent,TrustedLaunch)
# Register identity for an exe, then launch it however you want:
winapp create-debug-identity .\bin\Debug\myapp.exe
.\bin\Debug\myapp.exe # or F5 in your IDE
调试场景
场景 A:直接使用身份运行
最简单的工作流 - 生成,使用标识运行,完成。
winapp run .\build\Debug
Winapp 将文件夹注册为松散布局包并启动应用。 需要标识的 API 会立即工作。 这包括大多数开发和测试方案。
对于当前终端中需要 stdin/stdout 的 控制台应用 ,请添加 --with-alias:
winapp run .\build\Debug --with-alias
方案 B:将调试器附加到正在运行的应用
使用 winapp run 启动,记录 PID,然后连接 IDE 的调试器。
winapp run .\build\Debug
# Output: Process ID: 12345
然后在 IDE 中:
- VS Code:运行和调试→选择“附加”配置(请参阅以下 IDE 设置 )
-
WinDbg:
windbg -p 12345
限制: 在附加之前,你将错过运行的任何代码。 对于启动调试,请使用方案 D (
create-debug-identity)。
方案 C:注册标识,然后通过 IDE 的 AUMID 或别名启动
使用 --no-launch 注册包,然后通过 IDE 中 AUMID(由 run 报告)或 执行别名 启动应用程序。
步骤 1: 注册包而不启动:
winapp run .\build\Debug --no-launch
步骤 2: 将 IDE 配置为通过 AUMID 或 执行别名 (而不是直接执行)启动。
- 使用 AUMID 启动:使用命令
start shell:AppsFolder\<AUMID>。winapp run在注册应用时输出 AUMID。 - 使用别名启动:必须在清单中定义别名(
Package.appxmanifest首选,appxmanifest.xml也受支持)。
重要: 在生成文件夹中启动 exe 不会 为其提供标识。 应用必须通过 AUMID 激活或其执行别名启动。 这就是松散布局包的工作方式 - 标识与激活路径(而不是 exe 文件)相关联。
方案 D:使用标识从 IDE 启动(启动调试)
这是 使用完全 IDE 控件调试启动代码 的最佳方法 - IDE 的调试器从第一个指令控制进程,无论启动方式如何,exe 都有标识。
winapp create-debug-identity .\build\Debug\myapp.exe
现在,从终端、VS Code 的 F5、脚本中以任意方式启动 exe。 exe 具有标识,因为Windows注册了 sparse 包直接指向它。
它与
winapp run的区别在于: 使用create-debug-identity,标识依靠 exe 本身(借助Add-AppxPackage -ExternalLocation)。 使用winapp run时,标识绑定到松散的布局包 - 应用必须通过 AUMID 或别名启动。 当您需要 IDE 直接启动和调试 exe 时,create-debug-identity是更佳的选择。
这也是 电子应用 的最佳方法,其中 exe 路径与源目录不同。
方案 E:捕获调试输出和故障诊断
内联捕获OutputDebugString消息和首次机会异常。 框架噪声(WinUI、COM、DirectX 内部跟踪)被从控制台中筛除,因此仅显示应用的调试消息。 所有内容仍会写入日志文件,以便进行全面调查。
如果应用崩溃,将自动捕获和分析小型内存转储:
winapp run .\build\Debug --debug-output
在崩溃时,输出包括异常类型、消息以及堆栈跟踪,其中包含的源文件和行号是从生成输出文件夹中的 PDB 解析的。 可以在没有外部工具的情况下,立即分析托管代码(.NET)崩溃。 本机 (C++/WinRT) 崩溃时显示模块名称和偏移量;添加 --symbols 来下载完整函数名称的 PDB 符号:
winapp run .\build\Debug --debug-output --symbols
重要: 这会附加 winapp 作为调试器。 Windows仅允许每个进程一个调试器,因此无法同时附加Visual Studio、VS Code 或 WinDbg。
IDE 设置
VS Code
WinApp VS Code 扩展提供了一种自定义的winapp调试类型,它通过包身份启动应用并附加调试器,只需按一下F5。
使用身份进行一键 F5 调试
将 winapp 启动配置添加到 .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "winapp",
"request": "launch",
"name": "WinApp: Launch and Attach"
}
]
}
按 F5 时:
- 该扩展将扫描工作区以查找包含
.exe文件的生成输出目录。 - 选择要运行的生成文件夹(或设置为
inputFolder跳过提示)。 - 通过
winapp run启动你的应用以提供其程序包标识。 - 子调试会话使用指定的调试器附加到正在运行的进程。
调试器附加后,你将获得完整的 VS Code 调试体验 - 通过单击编辑器的行号区域设置断点,逐行单步执行代码 (F10)、单步进入函数 (F11)、在变量窗格中检查变量,并在调试控制台中计算表达式。 应用在整个过程中都使用包标识运行,因此依赖于标识的 API 的行为与生产中的行为完全相同。
重要: 调试
winapp类型 不会 自动生成项目。 进行代码更改后,在按 F5 之前重新生成。
使用 preLaunchTask 自动化构建
为了避免忘记重新构建项目,请在每次调试会话之前添加一个 preLaunchTask 来构建项目。
- 在
.vscode/tasks.json中定义生成任务(例如.NET):{ "version": "2.0.0", "tasks": [ { "label": "build", "command": "dotnet", "type": "process", "args": ["build", "${workspaceFolder}"], "problemMatcher": "$msCompile" } ] } - 在
launch.json中引用此内容。{ "type": "winapp", "request": "launch", "name": "WinApp: Launch and Attach", "preLaunchTask": "build" }
配置属性
| 财产 | 类型 | 违约 | Description |
|---|---|---|---|
inputFolder |
字符串 | 包含您的应用程序二进制文件的生成输出文件夹的路径(例如,${workspaceFolder}/bin/Debug/net8.0-windows10.0.22621)。 如果未设置,系统会提示你选择文件夹。 |
|
manifest |
字符串 | AppX 清单文件的路径(例如,AppxManifest.xml或Package.appxmanifestappxmanifest.xml)。 如果未设置,CLI 将从输入文件夹或当前目录自动检测。 |
|
debuggerType |
字符串 | coreclr |
要使用的基础调试器(coreclr或cppvsdbgnode)。 |
workingDirectory |
字符串 | 工作区文件夹 | 应用程序的工作目录。 |
args |
字符串 | 要传递给应用程序的命令行参数。 | |
outputAppxDirectory |
字符串 | 松散布局包的输出目录。 默认为输入文件夹中的文件夹 AppX 。 |
|
port |
number | 9229 |
(node 仅) 用于 Node.js --inspect 侦听器和附加连接的端口。 当默认端口已在使用时重写。 |
支持的调试器
debuggerType |
语言 | 所需的扩展 |
|---|---|---|
coreclr(默认值) |
C# / .NET | C# 开发工具包 |
cppvsdbg |
C/C++ | C/C++ |
node |
Node.js/Electron | 内置 |
C++ 项目的示例:
{
"type": "winapp",
"request": "launch",
"name": "WinApp: Launch C++ App",
"debuggerType": "cppvsdbg"
}
使用创建调试标识启动调试
如果需要从首条指令开始调试启动代码,F5 按键附加方法可能会错过初始代码。 请使用命令面板中的WinApp: 创建调试标识命令为您的可执行文件注册一个稀疏包,然后用标准调试器启动它:
{
"name": "Launch (with identity)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/bin/Debug/net8.0-windows10.0.22621/myapp.exe"
}
由于 create-debug-identity 在 exe 本身上注册了标识,因此应用无论如何启动都具有标识,包括通过标准的 VS Code 启动配置启动。
附加到正在运行的进程
如果您更喜欢从终端启动 winapp run 然后附加,请使用标准的附加配置。
{
"name": "Attach to Process",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
对于 C++/Rust,请使用 "type": "cppvsdbg" (MSVC) 或 "type": "lldb" (LLDB):
{
"name": "Attach (C++)",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
}
清理
完成测试后,请从命令面板运行 WinApp:注销包 ,以删除旁加载的开发包,而无需离开 VS Code。