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<int> 還是 CAtlArray<float>,都使用了相同的可視化效果。 如果 CAtlArray<float> 有特定的可視化條目,它的優先級將高於通用的條目。
<Type Name="ATL::CAtlArray<*>"> <DisplayString>{{Count = {m_nSize}}}</DisplayString> </Type>
可以使用 $T1 和 $T2 這樣的宏,在可視化條目中引用模板參數。 有關這些宏的示例,請參閱 Visual Studio 隨附的 .natvis 文件。
可視化工具類型匹配
如果無法驗證某個可視化條目,則使用下一個可用的可視化效果。
可繼承的特性
可選的 Inheritable 屬性用於指定,一個可視化效果是僅適用於一個基類型,還是適用於一個基類型和所有的派生類型。 Inheritable 的默認值為 true。
在下面的示例中,可視化效果僅適用於 BaseClass 類型:
<Type Name="Namespace::BaseClass" Inheritable="false"> <DisplayString>{{Count = {m_nSize}}}</DisplayString> </Type>
優先級特性
如果某個定義的分析失敗,可選的 Priority 屬性會指定使用備用定義的順序。 Priority 的值包括:Low、MediumLow、Medium、MediumHigh 和 High。 默認值是 Medium。 Priority屬性只區分同一個 .natvis 文件中的優先級。
下面的示例會首先分析與 2015 STL 匹配的條目。 如果分析失敗,就會使用 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>
可選特性
你可以將 Optional 屬性放在任一節點上。 如果某個可選節點內的某個子表達式的分析失敗,調試器就會忽略該節點,但會應用 Type 規則的其余部分。 在下面的類型中, [State] 不可選,但 [Exception] 可選。 如果 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>
條件屬性
可選的 Condition 屬性可用於許多可視化元素,指定何時使用可視化規則。 如果條件屬性內的表達式解析為 false,就不應用可視化規則。 如果其計算結果為 true,或者沒有 Condition 屬性,就會應用可視化規則。 你可以將此屬性用於可視化條目中的 if-else 邏輯。
例如,下面的可視化對象具有智能指針類型的兩個 DisplayString 元素。 當 _Myptr 成員為空時,第一個 DisplayString 元素的條件解析為 true,以便顯示該窗體。 如果 _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 特性
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 元素用於將可視化條目的范圍限定在特定模塊和版本內。 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>
不需要 Min 和 Max。 它們是可選屬性。 不支持通配符。
Name 特性的格式為filename. ext,如hello或some。 不允許使用路徑名。
DisplayString 元素
DisplayString 元素用於指定要顯示為變量值的字符串。 它接受混合表達式的任意字符串。 大括號內的所有內容都可解釋為表達式。 例如,以下 DisplayString 條目:
<Type Name="CPoint"> <DisplayString>{{x={x} y={y}}}</DisplayString> </Type>
表示 CPoint 類型的變量顯示如下圖所示:

在 DisplayString 表達式中,屬於 x 成員的 y 和 CPoint 位於大括號內,因此它們的值會被計算。 該示例還介紹了如何用雙層大括號({{ 或 }})對大括號進行轉義。
備注
DisplayString 元素是唯一接受任意字符串和大括號語法的元素。 所有其他可視化元素只接受調試器可以計算的表達式。
StringView 元素
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>
在調試過程中,可以選擇變量旁邊的放大鏡圖標,然后選擇 "文本可視化工具" 以顯示m_pszData指向的字符串。

表達式 {m_pszData,su} 包含一個 C++ 格式說明符 su,用於將值顯示為 Unicode 字符串。 有關詳細信息,請參閱 C++ 中的格式說明符。
Expand 元素
可選的 Expand 節點用於自定義當你在變量窗口中展開類型時,該可視化類型的子項。 Expand 節點接受用於定義子元素的子節點列表。
-
如果未在可視化條目中指定
Expand節點,子項將使用默認的展開規則。 -
如果指定的
Expand節點下面沒有子節點,類型就無法在調試器窗口中展開。
Item 展開
Item 元素是 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 元素中指定的表達式,然后在變量窗口的值列中顯示值。
調試器會為每個自定義展開自動創建 [Raw View] 節點。 上面的屏幕截圖中的 [Raw View] 節點是展開的,顯示了對象的默認原始視圖與其 Natvis 可視化效果的區別。 默認展開會為基類創建一個子樹,並將基類的所有數據成員以子項的形式列出。
備注
如果項元素的表達式指向復雜類型,則項節點本身是可展開的。
Size
使用 ArrayItems 節點,讓 Visual Studio 調試器將類型解釋為一個數組並顯示其各個元素。 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*元素類型的指針)。
數組下限的默認值為 0。 要修改此值,請使用 LowerBound 元素。 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指定數組的秩。Size元素接受將其替換為維索引以查找該維度中數組的長度的隱式$i參數。 在前面的示例中,表達式_M_extent.M_base[0]應為第0個維度指定長度,_M_extent._M_base[1]為1,依此類推。
下面是調試器窗口中顯示的一個二維 Concurrency::array 對象:

IndexListItems 展開
僅當數組元素在內存中連續排列時,才能使用 ArrayItems 展開。 調試器只需遞增其指針,就可以獲取下一個元素。 如果你需要操作值節點的索引,可以使用 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 展開
如果可視化類型表示一個鏈接列表,則調試器可以通過使用 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>
Size 元素引用該列表的長度。 HeadPointer 指向第一個元素, NextPointer 引用下一個元素,而 ValueNode 引用項的值。
調試器將在 NextPointer 節點元素(而不是父列表類型)環境中計算 ValueNode 和 LinkedListItems 表達式。 在前面的示例中,CAtlList 有一個 CNode 類(位於 atlcoll.h 中),它是鏈接列表的節點。 m_pNext 和 m_element 是 CNode 類(而不是 CAtlList 類)的字段。
ValueNode 可以保留為空或使用 this 來引用 LinkedListItems 節點本身。
CustomListItems 展開
CustomListItems 展開允許編寫自定義邏輯,以遍歷數據結構(如哈希表)。 使用 CustomListItems 來可視化數據結構,這些數據結構可以使用 C++ 表達式進行所有運算,但不太適合 ArrayItems、IndexListItems 或 LinkedListItems 模式。
借助在展開內定義的變量和對象,你可以在 Exec 展開中使用 CustomListItems 來執行內部代碼。 可以將邏輯運算符、算術運算符和賦值運算符與 Exec 一起使用。 不能使用 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 節點遍歷該樹並顯示其子級。 下面是使用 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>
語法類似於 LinkedListItems 節點。 LeftPointer、RightPointer 和 ValueNode 是在樹節點類的上下文中計算的。 ValueNode 可以保留為空或使用 this 來引用 TreeItems 節點本身。
ExpandedItem 展開
通過將基類或數據成員的屬性顯示為可視化類型的子項,ExpandedItem 元素生成了一個聚合的子視圖。 調試器將計算指定的表達式,並將結果的子節點附加到該可視化類型的子列表中。
例如,智能指針類型 auto_ptr<vector<int>> 通常顯示為:

要查看矢量的值,就必須在變量窗口中穿過 _Myptr 成員,向下深入兩個級別。 通過添加 ExpandedItem 元素,就可以從層次結構中去除 _Myptr 變量並直接查看矢量元素:
<Type Name="std::auto_ptr<*>"> <DisplayString>auto_ptr {*_Myptr}</DisplayString> <Expand> <ExpandedItem>_Myptr</ExpandedItem> </Expand> </Type>

下面的示例介紹了如何將基類的屬性聚合到一個派生類中。 假定 CPanel 類派生自 CFrameworkElement。 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 格式說明符肯定在這。 否則,*(CFrameworkElement*)this 表達式將導致再次應用 CPanel 可視化,因為默認可視化類型匹配規則認為它是最適合的類型。 使用nd格式說明符指示調試器使用基類可視化,如果基類沒有可視化效果,則使用默認擴展。
Synthetic Item 展開
ExpandedItem 元素通過消除層次結構提供更簡單的數據視圖,Synthetic 節點則恰好相反。 它允許您創建不是表達式結果的人工子元素。 人工智能元素可以具有其自己的子元素。 在下面的示例中, 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 元素
借助 HResult 元素,你可以自定義顯示在調試器窗口中的 HRESULT 信息。 HRValue 元素必須包含要自定義的 HRESULT 的 32 位值。 HRDescription 元素包含要顯示在調試器窗口中的信息。
<HResult Name="MY_E_COLLECTION_NOELEMENTS"> <HRValue>0xABC0123</HRValue> <HRDescription>No elements in the collection.</HRDescription> </HResult>
UIVisualizer 元素
UIVisualizer 元素用於向調試器注冊圖形可視化工具插件。 圖形可視化工具會創建一個對話框或其他界面,用符合其數據類型的方式顯示變量或對象。 可視化工具插件必須被編寫為 VSPackage,並且必須公開一項調試器可以使用的服務。 .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>
-
ServiceId-Id屬性對用來標識UIVisualizer。ServiceId是可視化工具包公開的服務的 GUID。 如果服務提供了多個可視化工具,Id是用來區分它們的唯一標識符。 在上面的示例中,同一個可視化工具服務提供了兩個可視化工具。 -
MenuName屬性用於定義可視化工具名稱,該名稱會顯示在調試器的放大鏡圖標旁邊的下拉列表中。 例如:
.natvis 文件中定義的每種類型都必須明確列出能夠顯示它的所有 UI 可視化工具。 調試器會將類型條目中的可視化工具引用與注冊的可視化工具相匹配。 例如,下面的 std::vector 類型條目引用的是前一個示例中的 UIVisualizer。
<Type Name="std::vector<int,*>"> <UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" /> </Type>
你可以在用於查看內存中位圖的圖像監視擴展中查看 UIVisualizer 的示例。
CustomVisualizer 元素
CustomVisualizer 是一個擴展點,用於指定你編寫的 VSIX 擴展,以便在 Visual Studio 代碼中控制可視化效果。 有關編寫 VSIX 擴展的更多信息,請參閱 Visual Studio SDK。
編寫自定義可視化工具比 XML Natvis 定義要費事得多,但 Natvis 在支持方面的限制對你沒有影響。 自定義可視化工具有權訪問所有的調試器擴展性 API,因此可以查詢和修改調試對象進程,也可以與 Visual Studio 的其他部分通信。
可以在 Condition 元素上使用 IncludeView、ExcludeView 和 CustomVisualizer 屬性。
限制
Natvis 自定義項適用於類和結構,但不能使用 typedef。
Natvis 不支持用於基元類型的可視化工具(例如 int、bool)或指向基元類型的指針。 在此方案中,一種選擇是使用適合用例的格式說明符。 例如,如果您在代碼中使用 double* mydoublearray,則可以在調試器的 "監視" 窗口中使用數組格式說明符,如表達式 mydoublearray, [100],這將顯示前100個元素。
