Natvis フレームワークを使用してデバッガーで C++ オブジェクトのカスタム ビューを作成する
Visual Studio Natvis フレームワークは、ローカル ウィンドウや ウォッチ ウィンドウ、DataTipsなど、デバッガー変数ウィンドウでのネイティブ型の表示方法をカスタマイズします。 Natvis の視覚化は、作成した型をデバッグ中に見えるようにするのに役立ちます。
Natvis は、以前のバージョンの Visual Studio の autoexp.dat ファイルを XML 構文、優れた診断、バージョン管理、および複数のファイルサポートに置き換えます。
手記
Natvis のカスタマイズはクラスと構造体で動作しますが、typedef では機能しません。
Natvis の視覚化
Natvis フレームワークを使用して、作成する型の視覚化ルールを作成し、開発者がデバッグ中に見やすくします。
たとえば、次の図は、カスタム視覚化が適用されていないデバッガー ウィンドウ Windows::UI::XAML::Controls::TextBox 型の変数を示しています。
強調表示された行には、TextBox
クラスの Text
プロパティが表示されます。 複雑なクラス階層を使用すると、このプロパティを見つけにくくなります。 デバッガーはカスタム文字列型を解釈する方法を知らないので、テキスト ボックス内に保持されている文字列が表示されません。
Natvis カスタム ビジュアライザー ルールが適用されている場合、変数ウィンドウでは同じ TextBox
がはるかに簡単に見えます。 クラスの重要なメンバーが一緒に表示され、デバッガーにはカスタム文字列型の基になる文字列値が表示されます。
ビジュアライザーを使用して
C++ プロジェクトで .natvis ファイルを使用する
Natvis .natvis ファイルを使用して視覚化ルールを指定します。
.natvis ファイルの基本的な構造は、視覚化エントリを表す 1 つ以上の Type
要素です。 各 Type
要素の完全修飾名は、Name
属性で指定されます。
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="MyNamespace::CFoo">
.
.
</Type>
<Type Name="...">
.
.
</Type>
</AutoVisualizer>
Visual Studio には、<VS Installation Folder>\Common7\Packages\Debugger\Visualizers フォルダーに .natvis ファイルがいくつか用意されています。 これらのファイルには、多くの一般的な型の視覚化ルールがあり、新しい型の視覚化を作成する例として使用できます。
.natvis ファイルを C++ プロジェクトに追加する
.natvis ファイルを任意の C++ プロジェクトに追加できます。
新しい .natvis ファイルを追加するには:
ソリューション エクスプローラーで C++ プロジェクト ノード
選択し、[プロジェクト] [新しい項目 の追加]選択するか、プロジェクトを右クリックして [ 新しい項目の追加] 選択します。 すべての項目テンプレートが表示されない場合は、[すべてのテンプレートの表示] を選択します。
[
新しい項目の追加 ] ダイアログボックスで、Visual C++ユーティリティ デバッガー視覚化ファイル (.natvis) 選択します。 ファイルに名前を付け、を選択して「を追加」を選びます。
新しいファイル ソリューション エクスプローラーに追加され、Visual Studio ドキュメント ウィンドウで開きます。
Visual Studio デバッガーは、C++ プロジェクト .natvis ファイルを自動的に読み込み、既定では、プロジェクトのビルド時に .pdb ファイルにも含めます。 ビルドされたアプリをデバッグすると、プロジェクトを開いていない場合でも、デバッガーは .pdb ファイルから .natvis ファイルを読み込みます。 .pdbに .natvis ファイルを含めない場合は、ビルドされた .pdb ファイルから除外できます。
.pdbから .natvis ファイルを除外するには:
ソリューション エクスプローラーで
.natvis ファイル選択し、 プロパティ アイコンを選択するか、ファイルを右クリックして [プロパティ]選択します。 ビルド から除外
の横にある矢印をクリックしてドロップダウンリストを表示し、[はい] を選択した後、[OK] を選択します。
手記
実行可能プロジェクトをデバッグするには、ソリューション項目を使用して、.pdbに含まれていない .natvis ファイルを追加します。C++ プロジェクトは使用できません。
手記
.pdb から読み込まれた Natvis 規則、.pdb が参照するモジュール内の型にのみ適用されます。 たとえば、module1.pdb Test
という名前のクラスも定義されている場合、Module1.pdb Natvis エントリは適用されません。
VSIX パッケージを使用して .natvis ファイルをインストールして登録するには:
VSIX パッケージで .natvis ファイルをインストールして登録できます。 インストールされている場所に関係なく、登録されているすべての .natvis ファイルは、デバッグ中に自動的に検出されます。
VSIX パッケージに .natvis ファイルを含めます。 たとえば、次のプロジェクト ファイルの場合です。
<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0"> <ItemGroup> <VSIXSourceItem Include="Visualizer.natvis" /> </ItemGroup> </Project>
.natvis ファイルを source.extension.vsixmanifest ファイルに登録します。
<?xml version="1.0" encoding="utf-8"?> <PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011"> <Assets> <Asset Type="NativeVisualizer" Path="Visualizer.natvis" /> </Assets> </PackageManifest>
Natvis ファイルの場所
.natvis ファイルを複数のプロジェクトに適用する場合は、ユーザー ディレクトリまたはシステム ディレクトリに追加できます。
.natvis ファイルは、次の順序で評価されます。
デバッグ中の .pdb に埋め込まれている .natvis ファイル (読み込まれたプロジェクトに同じ名前のファイルが存在する場合を除く)。
読み込まれた C++ プロジェクトまたは最上位レベルのソリューションに含まれる .natvis ファイル。 このグループには、クラス ライブラリを含むすべての読み込まれた C++ プロジェクトが含まれますが、他の言語のプロジェクトは含まれません。
VSIX パッケージを介してインストールおよび登録された .natvis ファイル。
- ユーザー固有の Natvis ディレクトリ (たとえば、%USERPROFILE%\Documents\Visual Studio 2022\Visualizers)。
- ユーザー固有の Natvis ディレクトリ (たとえば、%USERPROFILE%\Documents\Visual Studio 2019\Visualizers)。
- システム全体の Natvis ディレクトリ (<Microsoft Visual Studio インストール フォルダー>\Common7\Packages\Debugger\Visualizers)。 このディレクトリには、Visual Studio にインストールされている .natvis ファイルがあります。 管理者権限がある場合は、このディレクトリにファイルを追加できます。
デバッグ中に .natvis ファイルを変更する
プロジェクトのデバッグ中に、IDE で .natvis ファイルを変更できます。 デバッグと同じ Visual Studio インスタンスでファイルを開き、変更して保存します。 ファイルが保存されるとすぐに、ウォッチ と ローカル ウィンドウが更新され、変更が反映されます。
デバッグ中のソリューション .natvis ファイルを追加または削除することもできます。また、Visual Studio によって関連する視覚化が追加または削除されます。
デバッグ中には、.natvis ファイルが埋め込まれた .pdb ファイルを更新することはできません。
Visual Studio の外部で .natvis ファイルを変更した場合、その変更は自動的には反映されません。 デバッガー ウィンドウを更新するには、イミディエイト ウィンドウで .natvisreload コマンドを再評価します。 その後、デバッグ セッションを再起動せずに変更が有効になります。
.natvisreload コマンドを使用して、.natvis ファイルを新しいバージョンにアップグレードします。 たとえば、.natvis ファイルがソース管理にチェックインされ、他のユーザーが行った最近の変更を取得したい場合があります。
式と書式設定
Natvis 視覚化では、C++ 式を使用して、表示するデータ項目を指定します。 デバッガーでの C++ 式の機能強化と制限事項に加えて、Context 演算子 (C++)で説明されています。次の点に注意してください。
Natvis 式は、現在のスタック フレームではなく、視覚化されるオブジェクトのコンテキストで評価されます。 たとえば、Natvis 式の
x
は、視覚化対象のオブジェクト x という名前のフィールドを参照し、現在の関数の x という名前のローカル変数を参照しません。 Natvis 式ではローカル変数にアクセスできませんが、グローバル変数にはアクセスできます。Natvis 式では、関数の評価や副作用は許可されません。 関数呼び出しと代入演算子は無視されます。 デバッガー 組み込み関数 は副作用がないため、他の関数呼び出しが許可されていない場合でも、任意の Natvis 式から自由に呼び出すことができます。
式の表示方法を制御するには、「C++の書式指定子
で説明されている書式指定子のいずれかを使用できます。 ArrayItems 拡張の Size
式など、Natvis によってエントリが内部的に使用される場合、書式指定子は無視されます。
手記
Natvis ドキュメントは XML であるため、式でアンパサンド演算子、より大きい演算子、より小さい演算子、またはシフト演算子を直接使用することはできません。 項目の本文と条件ステートメントの両方で、これらの文字をエスケープする必要があります。 例えば:
\<Item Name="HiByte"\>(byte)(_flags \>\> 24),x\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \& 0xFF000000) == 0"\>"None"\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \& 0xFF000000) != 0"\>"Some"\</Item\>
Natvis ビュー
さまざまな Natvis ビューを定義して、さまざまな方法で型を表示できます。 たとえば、simple
という名前の簡略化されたビューを定義する std::vector
の視覚化を次に示します。 DisplayString
要素と ArrayItems
要素は既定のビューと simple
ビューに表示されますが、[size]
と [capacity]
の項目は simple
ビューには表示されません。
<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>
ウォッチ ウィンドウで、ビュー 書式指定子を使用して、代替ビューを指定します。 単純なビューは、vec、view(simple)として表示されます。
Natvis エラー
デバッガーが視覚化エントリでエラーを検出すると、デバッガーはそれらを無視します。 その型を生の形式で表示するか、別の適切な視覚化を選択します。 Natvis 診断を使用して、デバッガーが視覚化エントリを無視した理由を理解し、基になる構文と解析エラーを確認できます。
Natvis 診断を有効にするには:
- [ツール]>[オプション] (または [デバッグ]>[オプション]) >[デバッグ]>[出力ウィンドウ] で、[Natvis 診断メッセージ (C++ のみ)] を [エラー]、[警告]、または [詳細] に設定して、[OK] を選びます。
エラーは、出力 ウィンドウに表示されます。
Natvis 構文リファレンス
Natvis ファイルでは、次の要素と属性を使用できます。
AutoVisualizer 要素
AutoVisualizer
要素は、.natvis ファイルのルート ノードであり、名前空間 xmlns:
属性が含まれています。
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
.
.
</AutoVisualizer>
AutoVisualizer
要素には、Type、HResult、UIVisualizer、および CustomVisualizer の子を持つことができます。
型の要素
基本的な 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>
視覚化エントリのテンプレート パラメーターは、マクロ $T 1、$T 2 などを使用して参照できます。 これらのマクロの例については、Visual Studio に付属 .natvis ファイルを参照してください。
ビジュアライザーと型の対応付け
視覚化エントリの検証に失敗した場合は、次に使用可能な視覚化が使用されます。
継承可能な属性
省略可能な Inheritable
属性は、視覚エフェクトが基本型にのみ適用されるか、基本型とすべての派生型に適用されるかを指定します。 Inheritable
の既定値は true
です。
次の例では、視覚化は BaseClass
の種類にのみ適用されます。
<Type Name="Namespace::BaseClass" Inheritable="false">
<DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>
Priority 属性
省略可能な 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 属性
省略可能な Condition
属性は、多くの視覚エフェクト要素で使用でき、視覚化ルールを使用するタイミングを指定します。 条件属性内の式が false
に解決された場合、視覚化ルールは適用されません。 true
に評価された場合、または Condition
属性がない場合は、視覚化が適用されます。 この属性は、視覚化エントリの if-else ロジックに使用できます。
たとえば、次の視覚化には、スマート ポインター型の 2 つの DisplayString
要素があります。 _Myptr
メンバーが空の場合、フォームが表示されるように、最初の DisplayString
要素の条件が true
に解決されます。 _Myptr
メンバーが空でない場合、条件は false
に評価され、2 番目の 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
属性は、特定のビューに表示する要素または表示しない要素を指定します。 たとえば、std::vector
の次の Natvis 仕様では、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
要素は、名前の競合を回避し、不注意による不一致を軽減し、さまざまな種類のバージョンに対してさまざまな視覚化を可能にします。
異なるモジュールで使用される共通ヘッダー ファイルで型が定義されている場合、バージョン管理された視覚化は、その型が指定されたモジュール バージョンにある場合にのみ表示されます。
次の例では、視覚化は、バージョン 1.0 から 1.5 までの Windows.UI.Xaml.dll
で見つかった DirectUI::Border
の種類にのみ適用されます。
<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
の両方は必要ありません。 これらは省略可能な属性です。 ワイルドカード文字はサポートされていません。
DisplayString 要素
DisplayString
要素は、変数の値として表示する文字列を指定します。 これは、式と混合された任意の文字列を受け入れます。 中かっこ内のすべてのものは式として解釈されます。 たとえば、次の DisplayString
エントリです。
<Type Name="CPoint">
<DisplayString>{{x={x} y={y}}}</DisplayString>
</Type>
これは、CPoint
型の変数が次の図のように表示されることを意味します。
DisplayString
式では、CPoint
のメンバーである x
と y
が中かっこ内にあり、それらの値が評価されます。 この例では、二重波括弧 ({{
または }}
) を使用して波括弧を回避する方法も示しています。
手記
DisplayString
要素は、任意の文字列と中かっこ構文を受け入れる唯一の要素です。 その他のすべての視覚化要素は、デバッガーが評価できる式のみを受け入れます。
StringView 要素
StringView
要素は、デバッガーが組み込みのテキスト ビジュアライザーに送信できる値を定義します。 たとえば、ATL::CStringT
の種類に対して次の視覚化を指定します。
<Type Name="ATL::CStringT<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
</Type>
CStringT
オブジェクトは、次の例のように変数ウィンドウに表示されます。
CStringT DisplayString 要素
StringView
要素を追加すると、値をテキスト視覚化として表示できることをデバッガーに指示します。
<Type Name="ATL::CStringT<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
<StringView>m_pszData,su</StringView>
</Type>
デバッグ中に、変数の横にある虫眼鏡アイコンを選択し、テキスト ビジュアライザー
式
要素を展開
オプションの Expand
ノードは、変数ウィンドウで型を展開するときに、視覚化された型の子をカスタマイズします。 Expand
ノードは、子要素を定義する子ノードの一覧を受け入れます。
視覚化エントリで
Expand
ノードが指定されていない場合、子は既定の拡張ルールを使用します。Expand
ノードの下に子ノードが指定されていない場合、型はデバッガー ウィンドウで展開できません。
項目の拡張
Item
要素は、Expand
ノードの最も基本的で一般的な要素です。 Item
は、1 つの子要素を定義します。 たとえば、フィールドが top
、left
、right
、bottom
を持つ CRect
クラスには、次の視覚化エントリがあります。
<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
要素で指定された式を評価し、変数ウィンドウの Value 列に値を表示します。
デバッガーは、カスタム展開ごとに [Raw View] ノードを自動的に作成します。 上のスクリーンショットでは、展開された [Raw View] ノードが表示され、オブジェクトの既定の未加工ビューが Natvis の視覚エフェクトとどのように異なるかを示しています。 既定の拡張では、基底クラスのサブツリーが作成され、基本クラスのすべてのデータ メンバーが子として一覧表示されます。
手記
item 要素の式が複合型を指している場合、Item ノード自体は展開可能です。
ArrayItems の展開
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
は、変数ウィンドウで展開されたときに個々の要素を表示します。
std::vector の ArrayItems 拡張を使用した
ArrayItems
ノードには次のものが必要です。
- デバッガーが配列の長さを理解するための
Size
式 (整数に評価する必要があります)。 - 最初の要素を指す
ValuePointer
式 (void*
ではない要素型のポインターである必要があります)。
配列の下限の既定値は 0 です。 値をオーバーライドするには、LowerBound
要素を使用します。 Visual Studio に付属 .natvis ファイルには例があります。
手記
型自体 (CATLArray
など) でこの演算子が許可されていない場合でも、[]
演算子 (vector[i]
など) を、ArrayItems
を使用する任意の 1 次元配列視覚化と共に使用できます。
多次元配列を指定することもできます。 その場合、デバッガーは子要素を適切に表示するために少し多くの情報を必要とします。
<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>
<LowerBound>0</LowerBound>
</ArrayItems>
</Expand>
</Type>
Direction
は、配列が行優先順か列優先順かを指定します。Rank
配列のランクを指定します。Size
要素は暗黙的な$i
パラメーターを受け取ります。このパラメーターは、ディメンションインデックスに置き換えて、そのディメンション内の配列の長さを検索します。- 前の例では、式
_M_extent.M_base[0]
は 0 番目の次元の長さ、最初の次元_M_extent._M_base[1]
などを指定する必要があります。
- 前の例では、式
LowerBound
は、配列の各次元の下限を指定します。 多次元配列の場合は、暗黙的な$i
パラメーターを使用する式を指定できます。$i
パラメーターは次元インデックスに置き換えて、その次元内の配列の下限を見つけます。- 前の例では、すべてのディメンションが 0 から始まります。 ただし、下限として
($i == 1) ? 1000 : 100
した場合、0 番目のディメンションは 100 から始まり、最初のディメンションは 1000 から始まります。- たとえば
[100, 1000], [100, 1001], [100, 1002], ... [101, 1000], [101, 1001],...
など
- たとえば
- 前の例では、すべてのディメンションが 0 から始まります。 ただし、下限として
デバッガー ウィンドウでの 2 次元 Concurrency::array
オブジェクトの外観を次に示します。
を持つ 2 次元配列
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
の唯一の違いは、暗黙的な $i
パラメーターを持つ i番目の 要素への完全な式を受け取る ValueNode
です。
手記
型自体 (CATLArray
など) でこの演算子が許可されていない場合でも、[]
演算子 (vector[i]
など) を、IndexListItems
を使用する任意の 1 次元配列視覚化と共に使用できます。
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
は項目の値を参照します。
デバッガーは、親リストの種類ではなく、LinkedListItems
ノード要素のコンテキストで NextPointer
式と ValueNode
式を評価します。 前の例では、CAtlList
には、リンク リストのノードである CNode
クラス (atlcoll.h
にあります) があります。 m_pNext
と m_element
は、CAtlList
クラスではなく、その CNode
クラスのフィールドです。
ValueNode
は空のままにすることも、this
を使用して LinkedListItems
ノード自体を参照することもできます。
CustomListItems の展開
CustomListItems
拡張を使用すると、ハッシュテーブルなどのデータ構造を走査するためのカスタム ロジックを記述できます。 CustomListItems
を使用して、評価する必要があるすべてのものに対して C++ 式を使用できるデータ構造を視覚化しますが、ArrayItems
、IndexListItems
、または LinkedListItems
の金型には適していません。
Exec
を使用すると、展開で定義されている変数とオブジェクトを使用して、CustomListItems
展開内でコードを実行できます。 Exec
では、論理演算子、算術演算子、代入演算子を使用できます。 C++ の式エバリュエーターによってサポートされているデバッガー組み込み関数を除き、Exec
を使用して関数を評価することはできません。
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>>
通常は次のように表示されます。
既定
ベクトルの値を確認するには、変数ウィンドウで 2 つのレベルをドリルダウンし、_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 書式指定子を使用して、基底クラスの視覚化を使用するようにデバッガーに指示するか、基底クラスに視覚エフェクトがない場合は既定の拡張を使用します。
合成アイテムの展開
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>
内在的拡張
式から呼び出すことができるカスタム組み込み関数。 <Intrinsic>
要素には、IDkmIntrinsicFunctionEvaluator140 インターフェイスを介して関数を実装するデバッガー コンポーネントを伴う必要があります。 カスタム組み込み関数の実装の詳細については、「NatVis カスタム組み込み関数を実装する」を参照してください。
<Type Name="std::vector<*>">
<Intrinsic Name="size" Expression="(size_t)(_Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst)" />
<Intrinsic Name="capacity" Expression="(size_t)(_Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst)" />
<DisplayString>{{ size={size()} }}</DisplayString>
<Expand>
<Item Name="[capacity]" ExcludeView="simple">capacity()</Item>
<Item Name="[allocator]" ExcludeView="simple">_Mypair</Item>
<ArrayItems>
<Size>size()</Size>
<ValuePointer>_Mypair._Myval2._Myfirst</ValuePointer>
</ArrayItems>
</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
は、サービスが複数のビジュアライザーを提供する場合に、ビジュアライザーを区別する一意の識別子です。 前の例では、同じビジュアライザー サービスが 2 つのビジュアライザーを提供しています。MenuName
属性は、デバッガーの虫眼鏡アイコンの横にあるドロップダウン リストに表示するビジュアライザー名を定義します。 例えば:
.natvis ファイルで定義されている各型は、それを表示できる UI ビジュアライザーを明示的に一覧表示する必要があります。 デバッガーは、型エントリ内のビジュアライザー参照を登録されたビジュアライザーと照合します。 たとえば、次の std::vector
の型エントリは、前の例の UIVisualizer
を参照します。
<Type Name="std::vector<int,*>">
<UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
</Type>
メモリ内ビットマップの表示に使用される Image Watch 拡張機能の UIVisualizer
の例を確認できます。
CustomVisualizer 要素
CustomVisualizer
は、Visual Studio Code で視覚エフェクトを制御するために記述する VSIX 拡張機能を指定する機能拡張ポイントです。 VSIX 拡張機能の記述の詳細については、Visual Studio SDKを参照してください。
XML Natvis 定義よりもカスタム ビジュアライザーを記述する方がはるかに多くの作業ですが、Natvis が何を行うか、サポートしていないかについての制約から解放されます。 カスタム ビジュアライザーは、デバッガー拡張機能 API の完全なセットにアクセスできます。この API は、デバッグ対象プロセスのクエリと変更、または Visual Studio の他の部分との通信を行うことができます。
CustomVisualizer
要素では、Condition
、IncludeView
、および ExcludeView
属性を使用できます。
制限
Natvis のカスタマイズはクラスと構造体で動作しますが、typedef では機能しません。
Natvis では、プリミティブ型 (int
、bool
など) やプリミティブ型へのポインターのビジュアライザーはサポートされていません。 このシナリオでは、ユース ケースに適した 書式指定子 使用する方法があります。 たとえば、コードで double* mydoublearray
を使用する場合は、デバッガーの ウォッチ ウィンドウで配列書式指定子 (最初の 100 個の要素を示す式 mydoublearray, [100]
など) を使用できます。