适用于 C++/WinRT 的 Visual Studio 本机调试可视化 (natvis)
C++/WinRT Visual Studio 扩展 (VSIX) 提供 C++/WinRT 投影类型的 Visual Studio 本机调试可视化 (natvis)。 这提供了类似于 C# 调试的体验。
注意
有关 C++/WinRT Visual Studio 扩展 (VSIX) 的详细信息,请参阅 C++/WinRT 和 VSIX 的 Visual Studio 支持。
启用 natvis
Natvis 对于调试版本是自动启用的,因为在定义 _DEBUG 符号时会定义 WINRT_NATVIS 。
对于发布版本,下面介绍了如何选择它。
- 使用定义的符号 WINRT_NATVIS 编译代码。 这样会导出 WINRT_abi_val 函数,该函数为调试可视化工具提供在目标进程计算属性值的入口点。
- 生成完整的 PDB。 这是因为调试可视化工具使用 Visual Studio C++ 表达式计算器,而后者又需要所显示的属性类型的符号定义。
- 可视化的类型必须报告在可发现的元数据中定义的运行时类或接口。 它通过其 IInspectable::GetRuntimeClassName 的实现执行此操作。
综上所述,调试可视化工具最适合可在 C:\Windows\System32\WinMetadata
文件中找到元数据的 Windows 系统类型。 但它也支持用户定义的类型和远程调试,前提是你可正确地定位 .winmd
文件。
使用自定义元数据
调试可视化工具会查找用户定义的元数据(.winmd
文件)以及进程 .exe
。 它使用与 RoGetMetaDataFile 的算法相似的算法,探测完全限定的类型名称的后续子字符串。 例如,如果可视化的类型为 Contoso.Controls.Widget,则可视化工具会依次查找:
- Contoso.Controls.Widget.winmd
- Contoso.Controls.winmd
- Contoso.winmd
使用自定义元数据进行远程调试
进行远程调试时,进程 .exe
不在本地执行,因此自定义元数据(在上一部分中提及)搜索失败。 在这种情况下,可视化工具会回退到本地缓存文件夹 (%TEMP%
),以查找合适的 .winmd
文件。 如果找到,它会记录该文件的大小和日期,然后在远程调试目标中搜索同一 .winmd
以及该二进制文件。 如有必要,将下载远程文件,更新本地缓存。 此策略确保本地缓存的 .winmd
始终处于最新状态,并提供了一种方法,可以在无法远程找到 . 时winmd
手动缓存它(例如,如果 F5 部署未将其放在此处)。
有关缓存行为的示例,请参阅下面的故障排除部分。
疑难解答
调试可视化工具使用 Visual Studio C++ 表达式计算器,调用导出的 WINRT_abi_val 函数以获取属性值。 可视化工具通常可以捕获未处理的异常,并适当降级,同时在 Visual Studio 的“监视”窗口中显示“<Object uninitialized or information unavailable>”。
当可视化工具尝试计算其生存期范围外(如在构造之前)的局部变量时,这会非常有用。 在某些上下文(如单元测试)中,会安装未处理的异常筛选器。 这可能导致在 C++ 表达式计算器出现故障时进程终止。 为了防止出现故障,可视化工具在 WINRT_abi_val 中多次调用 VirtualQuery。
诊断
如果属性未正确显示,请在 Visual Studio 打开详细的 natvis 诊断(“工具”>“选项”>“调试”>“输出窗口”>“Natvis 诊断消息”),然后查看“输出”窗口中的 natvis 错误 。
以下摘录显示了探测 .winmd
文件的数次尝试,再从远程目标将其下载到本地缓存文件夹,然后加载该 .winmd
文件。
Natvis C++/WinRT: Looking for C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.Widget.winmd
Natvis C++/WinRT: Looking for C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.winmd
Natvis C++/WinRT: Downloading C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.winmd
Natvis C++/WinRT: Loaded C:\Users\...\AppData\Local\Temp\Consoso.Controls.winmd
如果可视化工具未找到 .winmd
文件,则会生成此错误:
Natvis C++/WinRT: Could not find metadata for Consoso.Controls.Widget
还有许多其他生成诊断的错误情况。
如果元数据可用,输出诊断将显示如下所示的许多调用:
Natvis C++/WinRT: WINRT_abi_val(*(::IUnknown**)0x32dd4ffc18, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
Natvis C++/WinRT: WINRT_abi_val(*(::IUnknown**)0x32dd4ffc18, L"{AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90}", -2).s,sh
第一个是对 IStringable.ToString 的调用,以获取复杂类型的字符串表示形式(未扩展的显示值)。
第二个是对 IInspectable::GetRuntimeClassName 的调用,以反映该类型的属性。
后续的 WINRT_abi_val 调用是对在该类型上发现的每个接口的属性计算。
调用 WINRT_abi_val
可使用 Visual Studio 的即时/命令窗口直接调用 WINRT_abi_val 以排除故障 。
例如,给定一个计划的变量 stringable,你可以计算其 IStringable.ToString:
>? WINRT_abi_val((::IUnknown*)&stringable, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
L"string"