Visual Studio Natvis フレームワークは、 ローカル ウィンドウや ウォッチ ウィンドウなどのデバッガー変数ウィンドウや DataTips でのネイティブ型の表示方法をカスタマイズします。 Natvis の視覚化は、作成した型をデバッグ中に見えるようにするのに役立ちます。
Natvis は、以前のバージョンの Visual Studio の autoexp.dat ファイルを XML 構文、優れた診断、バージョン管理、および複数のファイルサポートに置き換えます。
注
Natvis のカスタマイズはクラスと構造体で動作しますが、typedef では機能しません。
Natvis の視覚化
Natvis フレームワークを使用して、作成する型の視覚化ルールを作成し、開発者がデバッグ中に見やすくします。
たとえば、次の図は、カスタム視覚化が適用されていないデバッガー ウィンドウの Windows::UI::XAML::Controls::TextBox 型の変数を示しています。
強調表示された行には、Text クラスのTextBox プロパティが表示されます。 複雑なクラス階層を使用すると、このプロパティを見つけにくくなります。 デバッガーはカスタム文字列型を解釈する方法を知らないので、テキスト ボックス内に保持されている文字列が表示されません。
Natvis カスタム ビジュアライザー ルールが適用されている場合、変数ウィンドウでは同じ TextBox がはるかに簡単に見えます。 クラスの重要なメンバーが一緒に表示され、デバッガーにはカスタム文字列型の基になる文字列値が表示されます。
C++ プロジェクトで .natvis ファイルを使用する
Natvis では 、.natvis ファイルを使用して視覚化ルールを指定します。 .natvis ファイルは、拡張子が .natvis の XML ファイルです。 Natvis スキーマは、<VS インストール フォルダー>\Xml\Schemas\1033\natvis.xsd で定義されています。
.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 では、> フォルダーにいくつかの .natvis ファイルが用意されています。 これらのファイルには、多くの一般的な型の視覚化ルールがあり、新しい型の視覚化を作成する例として使用できます。
.natvis ファイルを C++ プロジェクトに追加する
.natvis ファイルは、任意の C++ プロジェクトに追加できます。
新しい .natvis ファイルを追加するには:
ソリューション エクスプローラーで C++ プロジェクト ノードを選択し、[プロジェクト]>[新しい項目の追加] を選択するか、プロジェクトを右クリックして [追加>新しい項目] を選択します。
すべての項目テンプレートが表示されない場合は、[すべてのテンプレートを 表示] を選択します。
[ 新しい項目の追加 ] ダイアログで、 Visual C++>Utility>Debugger 視覚化ファイル (.natvis) を選択します。
ファイルに名前を付 け、[追加] を選択します。
新しいファイルが ソリューション エクスプローラーに追加され、Visual Studio ドキュメント ウィンドウで開きます。
Visual Studio デバッガーは、C++ プロジェクトの .natvis ファイルを自動的に読み込みます。既定では、プロジェクトのビルド時に .pdb ファイルにも含まれます。 ビルドされたアプリをデバッグする場合、プロジェクトを開いていない場合でも、デバッガーは .pdb ファイルから .natvis ファイルを読み込みます。 .pdb に .natvis ファイルを含めない場合は、ビルドされた .pdb ファイルから除外できます。
.pdb から .natvis ファイルを除外するには:
ソリューション エクスプローラーで .natvis ファイルを選択し、[プロパティ] アイコンを選択するか、ファイルを右クリックして [プロパティ] を選択します。
ドロップダウン リストの [ ビルドから除外 ] の横にある矢印を選択し、[ はい] を選択し、[ OK] を選択します。
注
実行可能プロジェクトをデバッグする場合は、ソリューション項目を使用して、使用できる C++ プロジェクトがないため、.pdb にない .natvis ファイルを追加します。
注
.pdb から読み込まれた Natvis ルールは、.pdb が参照するモジュール内の型にのみ適用されます。 たとえば、Module1.pdb に Test という名前の型の Natvis エントリがある場合、Testの クラスにのみ適用されます。 別のモジュールで Test という名前のクラスも定義されている場合、 Module1.pdb Natvis エントリは適用されません。
VSIX パッケージを使用して .natvis ファイルをインストールして登録するには:
VSIX パッケージでは、 .natvis ファイルをインストールして登録できます。 インストールされている場所に関係なく、登録されているすべての .natvis ファイルは、デバッグ中に自動的に取得されます。
.natvis ファイルを VSIX パッケージに含めます。 たとえば、次のプロジェクト ファイルの場合です。
<?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>source.extension.vsixmanifest ファイルに .natvis ファイルを登録します。
<?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 ディレクトリ (たとえば、 \Documents\Visual Studio 2022\Visualizers%USERPROFILE%)。
- ユーザー固有の 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 で関連する視覚化を追加または削除したりすることもできます。
デバッグ中は、.pdb ファイルに埋め込まれている .natvis ファイルを更新できません。
Visual Studio の外部で .natvis ファイルを変更した場合、変更は自動的には反映されません。 デバッガー ウィンドウを更新するには、[イミディエイト] ウィンドウで .natvisreload コマンドを再評価します。 変更は、デバッグ セッションを再起動せずに有効になります。
また、 .natvisreload コマンドを使用して 、.natvis ファイルを新しいバージョンにアップグレードします。 たとえば、 .natvis ファイルがソース管理にチェックインされ、他のユーザーが行った最近の変更を取得する場合があります。
式と書式設定
Natvis 視覚化では、C++ 式を使用して、表示するデータ項目を指定します。 コンテキスト演算子 (C++) で説明されているデバッガーでの C++ 式の機能強化と制限事項に加えて、次の点に注意してください。
Natvis 式は、現在のスタック フレームではなく、視覚化されるオブジェクトのコンテキストで評価されます。 たとえば、Natvis 式の
xは、現在の関数の x という名前のローカル変数ではなく、視覚化されるオブジェクト内の x という名前のフィールドを参照します。 Natvis 式ではローカル変数にアクセスできませんが、グローバル変数にはアクセスできます。Natvis 式では、関数の評価や副作用は許可されません。 関数呼び出しと代入演算子は無視されます。 デバッガーの組み込み関数は副作用がないため、他の関数呼び出しが許可されていない場合でも、任意の Natvis 式から自由に呼び出すことができます。
式の表示方法を制御するには、C++ の書式指定子で説明されている書式 指定子のいずれかを使用できます。
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 ビューを定義して、さまざまな方法で型を表示できます。 たとえば、次のスニペットは、std::vectorという名前の簡略化されたビューを定義するsimpleの視覚化を示しています。
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 診断を有効にするには:
[ツール>オプション] ウィンドウを開き>Debugging>General] セクションを展開します。 Debug>Options アクションを実行すると、ペインが同じセクションに表示されます。
出力ウィンドウ>一般出力設定 で、Natvis 診断メッセージ (C++ のみ) オプションを エラー、警告、または 詳細 に設定します。
[ツール>オプション] ダイアログを開き、[デバッグ>] セクションを展開します。 Debug>Options アクションを実行すると、ダイアログが同じセクションに表示されます。
出力ウィンドウ>一般出力設定 で、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ノード) で型を展開したときの型のメンバーの外観。
テンプレート 化されたクラス
Name要素のType属性は、テンプレート化されたクラス名に使用できるワイルドカード文字としてアスタリスク*を受け取ります。
次の例では、オブジェクトが 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 のDirectUI::Borderで見つかった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属性は、hello.exeやsome.dll など、filename.ext 形式です。 パス名は許可されていません。
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} には、値を Unicode 文字列として表示するための C++ 書式指定子 su が含まれています。 詳細については、「 C++ の書式指定子」を参照してください。
要素を拡張する
省略可能な Expand ノードは、変数ウィンドウで型を展開するときに、視覚化された型の子をカスタマイズします。
Expand ノードは、子要素を定義する子ノードの一覧を受け入れます。
視覚化エントリで
Expandノードが指定されていない場合、子は既定の拡張ルールを使用します。Expandノードの下に子ノードが指定されていない場合、型はデバッガー ウィンドウで展開できません。
項目の展開
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 の視覚エフェクトとどのように異なるかを示しています。 既定の拡張では、基底クラスのサブツリーが作成され、基本クラスのすべてのデータ メンバーが子として一覧表示されます。
注
項目要素の式が複合型を指している場合、 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は、変数ウィンドウで展開されたときに個々の要素を表示します。
ArrayItems ノードには次のものが必要です。
- デバッガーが配列の長さを理解するための
Size式 (整数に評価する必要があります)。 - 最初の要素を指す
ValuePointer式 (void*ではない要素型のポインターである必要があります)。
配列の下限の既定値は 0 です。 値をオーバーライドするには、 LowerBound 要素を使用します。 Visual Studio に付属する .natvis ファイルには例があります。
注
型自体 ([] など) でこの演算子が許可されていない場合でも、vector[i]演算子 (ArrayItems など) を使用して、CATLArrayを使用する 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 オブジェクトの外観を次に示します。
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を使用する 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 は項目の値を参照します。
デバッガーは、親リストの種類ではなく、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では、論理演算子、算術演算子、代入演算子を使用できます。 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 ノードを使用してその子要素を表示できます。
std::map ノードを使用したTreeItemsの種類の視覚化を次に示します。
<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>
メモリ内ビットマップの表示に使用される UIVisualizer 拡張機能のの例を確認できます。
CustomVisualizer 要素
CustomVisualizer は、Visual Studio Code で視覚化を制御するために記述する VSIX 拡張機能を指定する機能拡張ポイントです。 VSIX 拡張機能の記述の詳細については、 Visual Studio SDK を参照してください。
XML Natvis 定義よりもカスタム ビジュアライザーを記述する方がはるかに多くの作業ですが、Natvis が何を行うか、サポートしていないかについての制約から解放されます。 カスタム ビジュアライザーは、デバッガー拡張機能 API の完全なセットにアクセスできます。この API は、デバッグ対象プロセスのクエリと変更、または Visual Studio の他の部分との通信を行うことができます。
Condition要素では、IncludeView、ExcludeView、およびCustomVisualizer属性を使用できます。
制限事項
Natvis のカスタマイズはクラスと構造体で動作しますが、typedef では機能しません。
Natvis では、プリミティブ型 ( int、 boolなど) やプリミティブ型へのポインターに対するビジュアライザーはサポートされていません。 このシナリオでは、ユース ケースに適した 書式指定子 を使用する方法があります。 たとえば、コードで double* mydoublearray を使用する場合は、デバッガーの ウォッチ ウィンドウで配列書式指定子 (最初の 100 個の要素を示す式 mydoublearray, [100]など) を使用できます。