AutoVisualizer 元素
AutoVisualizer 元素是 .natvis 文件的根节点,并包含命名空间 xmlns: 属性。
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
.
.
</AutoVisualizer>
AutoVisualizer 元素可以具有类型、 HResult、 UIVisualizer和CustomVisualizer子项。
Type 元素
基本 Type 如下例所示:
<Type Name="[fully qualified type name]">
<DisplayString Condition="[Boolean expression]">[Display value]</DisplayString>
<Expand>
...
</Expand>
</Type>
Type 元素指定:
-
可视化对象应使用的类型(
Name特性)。 -
该类型的对象的值是什么样的(
DisplayString元素)。 -
用户在变量窗口中展开类型时,该类型的成员应当以什么形式显示(
Expand节点)。
模板类
Type 元素的 Name 属性接受星号 * 作为可用于模板化类名的通配符。
如果 CAtlArray<float> 有特定的可视化条目,它的优先级将高于通用的条目。
<Type Name="ATL::CAtlArray<*>">
<DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>
有关这些宏的示例,请参阅 Visual Studio 随附的 .natvis 文件。
可视化工具类型匹配
如果无法验证某个可视化条目,则使用下一个可用的可视化效果。
可继承的特性
Inheritable 的默认值为 true。
在下面的示例中,可视化效果仅适用于 BaseClass 类型:
<Type Name="Namespace::BaseClass" Inheritable="false">
<DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>
优先级特性
Priority属性只区分同一个 .natvis 文件中的优先级。
如果分析失败,就会使用 STL 的 2013 版本的备用条目:
<!-- VC 2013 -->
<Type Name="std::reference_wrapper<*>" Priority="MediumLow">
<DisplayString>{_Callee}</DisplayString>
<Expand>
<ExpandedItem>_Callee</ExpandedItem>
</Expand>
</Type>
<!-- VC 2015 -->
<Type Name="std::reference_wrapper<*>">
<DisplayString>{*_Ptr}</DisplayString>
<Expand>
<Item Name="[ptr]">_Ptr</Item>
</Expand>
</Type>
可选特性
如果 MyNamespace::MyClass 包含名为 M_exceptionHolder 的字段,就会同时显示 [State] 节点和 [Exception] 节点,但如果不包含 _M_exceptionHolder 字段,就会只显示 [State] 节点。
<Type Name="MyNamespace::MyClass">
<Expand>
<Item Name="[State]">_M_State</Item>
<Item Name="[Exception]" Optional="true">_M_exceptionHolder</Item>
</Expand>
</Type>
条件属性
你可以将此属性用于可视化条目中的 if-else 逻辑。
如果 _Myptr 成员不为空,则条件的计算结果为 false,第二个 DisplayString 元素显示。
<Type Name="std::auto_ptr<*>">
<DisplayString Condition="_Myptr == 0">empty</DisplayString>
<DisplayString>auto_ptr {*_Myptr}</DisplayString>
<Expand>
<ExpandedItem>_Myptr</ExpandedItem>
</Expand>
</Type>
IncludeView 和 ExcludeView 特性
例如,在下面的 Natvis std::vector 规范中,simple 视图不显示 [size] 和 [capacity] 项。
<Type Name="std::vector<*>">
<DisplayString>{{ size={_Mylast - _Myfirst} }}</DisplayString>
<Expand>
<Item Name="[size]" ExcludeView="simple">_Mylast - _Myfirst</Item>
<Item Name="[capacity]" ExcludeView="simple">_Myend - _Myfirst</Item>
<ArrayItems>
<Size>_Mylast - _Myfirst</Size>
<ValuePointer>_Myfirst</ValuePointer>
</ArrayItems>
</Expand>
</Type>
可以针对类型和各个成员使用 IncludeView 和 ExcludeView 属性。
Version 元素
Version 元素有助于避免名称冲突、减少无意间的不匹配,还允许在不同的类型版本中使用不同的可视化效果。
如果某个由不同模块使用的公共头文件定义了一个类型,则只有当该类型位于指定的模块版本中时,版本化的可视化效果才会显示。
在下面的示例中,可视化效果只适用于在 DirectUI::Border 版本 1.0 到 1.5 中找到的 Windows.UI.Xaml.dll 类型。
<Type Name="DirectUI::Border">
<Version Name="Windows.UI.Xaml.dll" Min="1.0" Max="1.5"/>
<DisplayString>{{Name = {*(m_pDO->m_pstrName)}}}</DisplayString>
<Expand>
<ExpandedItem>*(CBorder*)(m_pDO)</ExpandedItem>
</Expand>
</Type>
不支持通配符。
不允许使用路径名。
DisplayString 元素
例如,以下 DisplayString 条目:
<Type Name="CPoint">
<DisplayString>{{x={x} y={y}}}</DisplayString>
</Type>
表示 CPoint 类型的变量显示如下图所示:
该示例还介绍了如何用双层大括号({{ 或 }})对大括号进行转义。
备注
所有其他可视化元素只接受调试器可以计算的表达式。
StringView 元素
例如,假设 ATL::CStringT 类型有以下可视化效果:
<Type Name="ATL::CStringT<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
</Type>
CStringT 对象将显示在一个变量窗口中,如下例所示:
添加 StringView 元素会告诉调试器,它可以将值显示为文本可视化。
<Type Name="ATL::CStringT<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
<StringView>m_pszData,su</StringView>
</Type>
有关详细信息,请参阅 C++ 中的格式说明符。
Expand 元素
Expand 节点接受用于定义子元素的子节点列表。
-
如果未在可视化条目中指定
Expand节点,子项将使用默认的展开规则。 -
如果指定的
Expand节点下面没有子节点,类型就无法在调试器窗口中展开。
Item 展开
例如,一个包含 CRect、top、left 和 right 字段的 bottom 类具有以下可视化条目:
<Type Name="CRect">
<DisplayString>{{top={top} bottom={bottom} left={left} right={right}}}</DisplayString>
<Expand>
<Item Name="Width">right - left</Item>
<Item Name="Height">bottom - top</Item>
</Expand>
</Type>
在调试器窗口中,CRect 类型如下例所示:
调试器将计算 Width 和 Height 元素中指定的表达式,然后在变量窗口的值列中显示值。
默认展开会为基类创建一个子树,并将基类的所有数据成员以子项的形式列出。
备注
如果项元素的表达式指向复杂类型,则项节点本身是可展开的。
Size
std::vector 的可视化效果是一个很好的示例:
<Type Name="std::vector<*>">
<DisplayString>{{size = {_Mylast - _Myfirst}}}</DisplayString>
<Expand>
<Item Name="[size]">_Mylast - _Myfirst</Item>
<Item Name="[capacity]">(_Myend - _Myfirst)</Item>
<ArrayItems>
<Size>_Mylast - _Myfirst</Size>
<ValuePointer>_Myfirst</ValuePointer>
</ArrayItems>
</Expand>
</Type>
std::vector 在变量窗口中展开时显示其自身的元素:
ArrayItems 节点必须具有:
- 用于使调试器了解数组长度的
Size表达式(必须计算为整数)。 - 一个
ValuePointer表达式,指向第一个元素(必须为非void*元素类型的指针)。
Visual Studio 随附的 .Natvis 文件中提供了示例。
备注
可以使用 [] 运算符(例如 vector[i])以及任何使用了 ArrayItems 的一维数组可视化效果,即使该类型本身(例如 CATLArray)不允许使用此运算符。
在这种情况下,调试器需要稍微详细地显示子元素:
<Type Name="Concurrency::array<*,*>">
<DisplayString>extent = {_M_extent}</DisplayString>
<Expand>
<Item Name="extent">_M_extent</Item>
<ArrayItems Condition="_M_buffer_descriptor._M_data_ptr != 0">
<Direction>Forward</Direction>
<Rank>$T2</Rank>
<Size>_M_extent._M_base[$i]</Size>
<ValuePointer>($T1*) _M_buffer_descriptor._M_data_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
Direction指定数组是采用行优先顺序还是列优先顺序。Rank指定数组的秩。- 在前面的示例中,表达式
_M_extent.M_base[0]应为第0个维度指定长度,_M_extent._M_base[1]为1,依此类推。
下面是调试器窗口中显示的一个二维 Concurrency::array 对象:
IndexListItems 展开
下面是 IndexListItems 节点的可视化处理:
<Type Name="Concurrency::multi_link_registry<*>">
<DisplayString>{{size = {_M_vector._M_index}}}</DisplayString>
<Expand>
<Item Name="[size]">_M_vector._M_index</Item>
<IndexListItems>
<Size>_M_vector._M_index</Size>
<ValueNode>*(_M_vector._M_array[$i])</ValueNode>
</IndexListItems>
</Expand>
</Type>
ArrayItems 和 IndexListItems 之间的唯一区别是 ValueNode,它期望带有隐式元素 参数的第 i$i 个元素的完整表达式。
备注
可以使用 [] 运算符(例如 vector[i])以及任何使用了 IndexListItems 的一维数组可视化效果,即使该类型本身(例如 CATLArray)不允许使用此运算符。
LinkedListItems 展开
以下 CAtlList 类型的可视化效果使用 LinkedListItems:
<Type Name="ATL::CAtlList<*,*>">
<DisplayString>{{Count = {m_nElements}}}</DisplayString>
<Expand>
<Item Name="Count">m_nElements</Item>
<LinkedListItems>
<Size>m_nElements</Size>
<HeadPointer>m_pHead</HeadPointer>
<NextPointer>m_pNext</NextPointer>
<ValueNode>m_element</ValueNode>
</LinkedListItems>
</Expand>
</Type>
HeadPointer 指向第一个元素, NextPointer 引用下一个元素,而 ValueNode 引用项的值。
m_pNext 和 m_element 是 CNode 类(而不是 CAtlList 类)的字段。
ValueNode 可以保留为空或使用 this 来引用 LinkedListItems 节点本身。
CustomListItems 展开
使用 CustomListItems 来可视化数据结构,这些数据结构可以使用 C++ 表达式进行所有运算,但不太适合 ArrayItems、IndexListItems 或 LinkedListItems 模式。
不能使用 Exec 来计算函数( C++表达式计算器支持的调试器内部函数除外)。
下面的 CAtlMap 可视化工具是一个很好的例子,其中的 CustomListItems 用得很恰当。
<Type Name="ATL::CAtlMap<*,*,*,*>">
<AlternativeType Name="ATL::CMapToInterface<*,*,*>"/>
<AlternativeType Name="ATL::CMapToAutoPtr<*,*,*>"/>
<DisplayString>{{Count = {m_nElements}}}</DisplayString>
<Expand>
<CustomListItems MaxItemsPerView="5000" ExcludeView="Test">
<Variable Name="iBucket" InitialValue="-1" />
<Variable Name="pBucket" InitialValue="m_ppBins == nullptr ? nullptr : *m_ppBins" />
<Variable Name="iBucketIncrement" InitialValue="-1" />
<Size>m_nElements</Size>
<Exec>pBucket = nullptr</Exec>
<Loop>
<If Condition="pBucket == nullptr">
<Exec>iBucket++</Exec>
<Exec>iBucketIncrement = __findnonnull(m_ppBins + iBucket, m_nBins - iBucket)</Exec>
<Break Condition="iBucketIncrement == -1" />
<Exec>iBucket += iBucketIncrement</Exec>
<Exec>pBucket = m_ppBins[iBucket]</Exec>
</If>
<Item>pBucket,na</Item>
<Exec>pBucket = pBucket->m_pNext</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
TreeItems 展开
下面是使用 TreeItems 节点的 std::map 类型的可视化效果:
<Type Name="std::map<*>">
<DisplayString>{{size = {_Mysize}}}</DisplayString>
<Expand>
<Item Name="[size]">_Mysize</Item>
<Item Name="[comp]">comp</Item>
<TreeItems>
<Size>_Mysize</Size>
<HeadPointer>_Myhead->_Parent</HeadPointer>
<LeftPointer>_Left</LeftPointer>
<RightPointer>_Right</RightPointer>
<ValueNode Condition="!((bool)_Isnil)">_Myval</ValueNode>
</TreeItems>
</Expand>
</Type>
ValueNode 可以保留为空或使用 this 来引用 TreeItems 节点本身。
ExpandedItem 展开
调试器将计算指定的表达式,并将结果的子节点附加到该可视化类型的子列表中。
例如,智能指针类型 auto_ptr<vector<int>> 通常显示为:
通过添加 ExpandedItem 元素,就可以从层次结构中去除 _Myptr 变量并直接查看矢量元素:
<Type Name="std::auto_ptr<*>">
<DisplayString>auto_ptr {*_Myptr}</DisplayString>
<Expand>
<ExpandedItem>_Myptr</ExpandedItem>
</Expand>
</Type>
CFrameworkElement 节点的可视化会将基 ExpandedItem 类的属性附加到 CPanel 类的子列表中,而不是重复这些属性。
<Type Name="CPanel">
<DisplayString>{{Name = {*(m_pstrName)}}}</DisplayString>
<Expand>
<Item Name="IsItemsHost">(bool)m_bItemsHost</Item>
<ExpandedItem>*(CFrameworkElement*)this,nd</ExpandedItem>
</Expand>
</Type>
使用nd格式说明符指示调试器使用基类可视化,如果基类没有可视化效果,则使用默认扩展。
Synthetic Item 展开
在下面的示例中, Concurrency::array 类型的可视化效果使用 Synthetic 节点向用户显示诊断消息:
<Type Name="Concurrency::array<*,*>">
<DisplayString>extent = {_M_extent}</DisplayString>
<Expand>
<Item Name="extent" Condition="_M_buffer_descriptor._M_data_ptr == 0">_M_extent</Item>
<ArrayItems Condition="_M_buffer_descriptor._M_data_ptr != 0">
<Rank>$T2</Rank>
<Size>_M_extent._M_base[$i]</Size>
<ValuePointer>($T1*) _M_buffer_descriptor._M_data_ptr</ValuePointer>
</ArrayItems>
<Synthetic Name="Array" Condition="_M_buffer_descriptor._M_data_ptr == 0">
<DisplayString>Array members can be viewed only under the GPU debugger</DisplayString>
</Synthetic>
</Expand>
</Type>
HResult 元素
HRDescription 元素包含要显示在调试器窗口中的信息。
<HResult Name="MY_E_COLLECTION_NOELEMENTS">
<HRValue>0xABC0123</HRValue>
<HRDescription>No elements in the collection.</HRDescription>
</HResult>
UIVisualizer 元素
.Natvis 文件包含插件的注册信息,例如名称、所公开服务的 GUID 以及它可以直观显示的类型。
下面是 UIVisualizer 元素的示例:
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}"
Id="1" MenuName="Vector Visualizer"/>
<UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}"
Id="2" MenuName="List Visualizer"/>
.
.
</AutoVisualizer>
-
在上面的示例中,同一个可视化工具服务提供了两个可视化工具。
-
例如:
例如,下面的 std::vector 类型条目引用的是前一个示例中的 UIVisualizer。
<Type Name="std::vector<int,*>">
<UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
</Type>
你可以在用于查看内存中位图的图像监视扩展中查看 UIVisualizer 的示例。
CustomVisualizer 元素
有关编写 VSIX 扩展的更多信息,请参阅 Visual Studio SDK。
自定义可视化工具有权访问所有的调试器扩展性 API,因此可以查询和修改调试对象进程,也可以与 Visual Studio 的其他部分通信。
可以在 Condition 元素上使用 IncludeView、ExcludeView 和 CustomVisualizer 属性。
限制
Natvis 自定义项适用于类和结构,但不能使用 typedef。
mydoublearray, [100],这将显示前100个元素。