C++/WinRT Visual Studio 扩展(VSIX)可为你提供 Visual Studio 对 C++/WinRT 投影类型的本机调试可视化(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 文件,它还可以支持用户定义的类型和远程调试。
使用自定义元数据
调试可视化工具会在进程 .exe 所在位置查找用户定义的元数据(.winmd 文件)。 它使用与 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<窗口中显示“>对象未初始化或信息不可用”。
当可视化工具尝试在其生存期范围之外评估局部变量时(例如,在构造之前),这非常有用。 在某些上下文(如单元测试)中,会安装未经处理的异常筛选器。 这可能会导致 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进行故障排除。
例如,给定投影变量 可字符串化,可以将其 IStringable.ToString 计算为:
>? WINRT_abi_val((::IUnknown*)&stringable, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
L"string"