次の方法で共有


Natvis フレームワークを使用してデバッガーで C++ オブジェクトのカスタム ビューを作成する

Visual Studio Natvis フレームワークは、ローカル ウィンドウや ウォッチ ウィンドウ、DataTipsなど、デバッガー変数ウィンドウでのネイティブ型の表示方法をカスタマイズします。 Natvis の視覚化は、作成した型をデバッグ中に見えるようにするのに役立ちます。

Natvis は、以前のバージョンの Visual Studio の autoexp.dat ファイルを XML 構文、優れた診断、バージョン管理、および複数のファイルサポートに置き換えます。

手記

Natvis のカスタマイズはクラスと構造体で動作しますが、typedef では機能しません。

Natvis の視覚化

Natvis フレームワークを使用して、作成する型の視覚化ルールを作成し、開発者がデバッグ中に見やすくします。

たとえば、次の図は、カスタム視覚化が適用されていないデバッガー ウィンドウ Windows::UI::XAML::Controls::TextBox 型の変数を示しています。

TextBox の既定の視覚化

強調表示された行には、TextBox クラスの Text プロパティが表示されます。 複雑なクラス階層を使用すると、このプロパティを見つけにくくなります。 デバッガーはカスタム文字列型を解釈する方法を知らないので、テキスト ボックス内に保持されている文字列が表示されません。

Natvis カスタム ビジュアライザー ルールが適用されている場合、変数ウィンドウでは同じ TextBox がはるかに簡単に見えます。 クラスの重要なメンバーが一緒に表示され、デバッガーにはカスタム文字列型の基になる文字列値が表示されます。

ビジュアライザーを使用して ビジュアライザーを使用した TextBox データ

C++ プロジェクトで .natvis ファイルを使用する

Natvis .natvis ファイルを使用して視覚化ルールを指定します。 .natvis ファイルは、拡張子が .natvis の XML ファイルです。 Natvis スキーマは、<VS Installation Folder>\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 には、<VS Installation Folder>\Common7\Packages\Debugger\Visualizers フォルダーに .natvis ファイルがいくつか用意されています。 これらのファイルには、多くの一般的な型の視覚化ルールがあり、新しい型の視覚化を作成する例として使用できます。

.natvis ファイルを C++ プロジェクトに追加する

.natvis ファイルを任意の C++ プロジェクトに追加できます。

新しい .natvis ファイルを追加するには:

  1. ソリューション エクスプローラーで C++ プロジェクト ノード 選択し、[プロジェクト][新しい項目の追加] 選択するか、プロジェクトを右クリックして [新しい項目の追加]選択します。

    すべての項目テンプレートが表示されない場合は、[すべてのテンプレートの表示] を選択します。

  2. [新しい項目の追加] ダイアログボックスで、Visual C++ユーティリティデバッガー視覚化ファイル (.natvis)選択します。

  3. ファイルに名前を付け、を選択して「を追加」を選びます。

    新しいファイル ソリューション エクスプローラーに追加され、Visual Studio ドキュメント ウィンドウで開きます。

Visual Studio デバッガーは、C++ プロジェクト .natvis ファイルを自動的に読み込み、既定では、プロジェクトのビルド時に .pdb ファイルにも含めます。 ビルドされたアプリをデバッグすると、プロジェクトを開いていない場合でも、デバッガーは .pdb ファイルから .natvis ファイルを読み込みます。 .pdb.natvis ファイルを含めない場合は、ビルドされた .pdb ファイルから除外できます。

.pdbから .natvis ファイルを除外するには:

  1. ソリューション エクスプローラーで .natvis ファイル 選択し、プロパティ アイコンを選択するか、ファイルを右クリックして [プロパティ]選択します。

  2. ビルド から除外 の横にある矢印をクリックしてドロップダウンリストを表示し、[はい] を選択した後、[OK] を選択します。

手記

実行可能プロジェクトをデバッグするには、ソリューション項目を使用して、.pdbに含まれていない .natvis ファイルを追加します。C++ プロジェクトは使用できません。

手記

.pdb から読み込まれた Natvis 規則.pdb が参照するモジュール内の型にのみ適用されます。 たとえば、module1.pdb という名前の型の Natvis エントリがある場合、Module1.dll クラスにのみ適用されます。 別のモジュールで Testという名前のクラスも定義されている場合、Module1.pdb Natvis エントリは適用されません。

VSIX パッケージを使用して .natvis ファイルをインストールして登録するには:

VSIX パッケージで .natvis ファイルをインストールして登録できます。 インストールされている場所に関係なく、登録されているすべての .natvis ファイルは、デバッグ中に自動的に検出されます。

  1. 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>
    
  2. .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 ファイルは、次の順序で評価されます。

  1. デバッグ中の .pdb に埋め込まれている .natvis ファイル (読み込まれたプロジェクトに同じ名前のファイルが存在する場合を除く)。

  2. 読み込まれた C++ プロジェクトまたは最上位レベルのソリューションに含まれる .natvis ファイル。 このグループには、クラス ライブラリを含むすべての読み込まれた C++ プロジェクトが含まれますが、他の言語のプロジェクトは含まれません。

  3. VSIX パッケージを介してインストールおよび登録された .natvis ファイル。

  1. ユーザー固有の Natvis ディレクトリ (たとえば、%USERPROFILE%\Documents\Visual Studio 2022\Visualizers)。
  1. ユーザー固有の Natvis ディレクトリ (たとえば、%USERPROFILE%\Documents\Visual Studio 2019\Visualizers)。
  1. システム全体の 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 \&gt;\&gt; 24),x\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \&amp; 0xFF000000) == 0"\>"None"\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \&amp; 0xFF000000) != 0"\>"Some"\</Item\>

Natvis ビュー

さまざまな Natvis ビューを定義して、さまざまな方法で型を表示できます。 たとえば、simpleという名前の簡略化されたビューを定義する std::vector の視覚化を次に示します。 DisplayString 要素と ArrayItems 要素は既定のビューと simple ビューに表示されますが、[size][capacity] の項目は simple ビューには表示されません。

<Type Name="std::vector&lt;*&gt;">
    <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 要素には、TypeHResultUIVisualizer、および CustomVisualizer の子を持つことができます。

型の要素

基本的な Type は次の例のようになります。

<Type Name="[fully qualified type name]">
  <DisplayString Condition="[Boolean expression]">[Display value]</DisplayString>
  <Expand>
    ...
  </Expand>
</Type>

Type 要素は次を指定します。

  1. 視覚化を使用する必要がある種類 (Name 属性)。

  2. その型のオブジェクトの値の外観 (DisplayString 要素)。

  3. ユーザーが変数ウィンドウ (Expand ノード) で型を展開したときの型のメンバーの外観。

テンプレート 化されたクラス

Type 要素の Name 属性は、テンプレート化されたクラス名に使用できるワイルドカード文字としてアスタリスク * を受け取ります。

次の例では、オブジェクトが CAtlArray<int>CAtlArray<float>かに関係なく、同じ視覚化が使用されます。 CAtlArray<float>の特定の視覚化エントリがある場合は、汎用エントリよりも優先されます。

<Type Name="ATL::CAtlArray&lt;*&gt;">
    <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 の使用可能な値は、LowMediumLowMediumMediumHigh、および Highです。 既定値は Mediumです。 Priority 属性は、同じ .natvis ファイル内の優先順位のみを区別します。

次の例では、最初に 2015 STL に一致するエントリを解析します。 解析に失敗した場合、STL の 2013 バージョンの代替エントリが使用されます。

<!-- VC 2013 -->
<Type Name="std::reference_wrapper&lt;*&gt;" Priority="MediumLow">
     <DisplayString>{_Callee}</DisplayString>
    <Expand>
        <ExpandedItem>_Callee</ExpandedItem>
    </Expand>
</Type>

<!-- VC 2015 -->
<Type Name="std::reference_wrapper&lt;*&gt;">
    <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&lt;*&gt;">
  <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&lt;*&gt;">
    <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>

MinMaxの両方は必要ありません。 これらは省略可能な属性です。 ワイルドカード文字はサポートされていません。

属性は、hello.exesome.dllなど、filename.ext形式です。 パス名は使用できません。

DisplayString 要素

DisplayString 要素は、変数の値として表示する文字列を指定します。 これは、式と混合された任意の文字列を受け入れます。 中かっこ内のすべてのものは式として解釈されます。 たとえば、次の DisplayString エントリです。

<Type Name="CPoint">
  <DisplayString>{{x={x} y={y}}}</DisplayString>
</Type>

これは、CPoint 型の変数が次の図のように表示されることを意味します。

DisplayString 要素を使用する

DisplayString 式では、CPointのメンバーである xyが中かっこ内にあり、それらの値が評価されます。 この例では、二重波括弧 ({{ または }}) を使用して波括弧を回避する方法も示しています。

手記

DisplayString 要素は、任意の文字列と中かっこ構文を受け入れる唯一の要素です。 その他のすべての視覚化要素は、デバッガーが評価できる式のみを受け入れます。

StringView 要素

StringView 要素は、デバッガーが組み込みのテキスト ビジュアライザーに送信できる値を定義します。 たとえば、ATL::CStringT の種類に対して次の視覚化を指定します。

<Type Name="ATL::CStringT&lt;wchar_t,*&gt;">
  <DisplayString>{m_pszData,su}</DisplayString>
</Type>

CStringT オブジェクトは、次の例のように変数ウィンドウに表示されます。

CStringT DisplayString 要素CStringT DisplayString 要素を

StringView 要素を追加すると、値をテキスト視覚化として表示できることをデバッガーに指示します。

<Type Name="ATL::CStringT&lt;wchar_t,*&gt;">
  <DisplayString>{m_pszData,su}</DisplayString>
  <StringView>m_pszData,su</StringView>
</Type>

デバッグ中に、変数の横にある虫眼鏡アイコンを選択し、テキスト ビジュアライザー 選択して、m_pszData が指す文字列を表示できます。

StringView ビジュアライザーを含む CStringT データ

には、値を Unicode 文字列として表示するために、suC++ 書式指定子が含まれています。 詳細については、「C++での書式指定子の 」を参照してください。

要素を展開

オプションの Expand ノードは、変数ウィンドウで型を展開するときに、視覚化された型の子をカスタマイズします。 Expand ノードは、子要素を定義する子ノードの一覧を受け入れます。

  • 視覚化エントリで Expand ノードが指定されていない場合、子は既定の拡張ルールを使用します。

  • Expand ノードの下に子ノードが指定されていない場合、型はデバッガー ウィンドウで展開できません。

項目の拡張

Item 要素は、Expand ノードの最も基本的で一般的な要素です。 Item は、1 つの子要素を定義します。 たとえば、フィールドが topleftrightbottom を持つ 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 の種類は次の例のようになります。

Item 要素の展開を含む CRect

デバッガーは、Width 要素と Height 要素で指定された式を評価し、変数ウィンドウの Value 列に値を表示します。

デバッガーは、カスタム展開ごとに [Raw View] ノードを自動的に作成します。 上のスクリーンショットでは、展開された [Raw View] ノードが表示され、オブジェクトの既定の未加工ビューが Natvis の視覚エフェクトとどのように異なるかを示しています。 既定の拡張では、基底クラスのサブツリーが作成され、基本クラスのすべてのデータ メンバーが子として一覧表示されます。

手記

item 要素の式が複合型を指している場合、Item ノード自体は展開可能です。

ArrayItems の展開

ArrayItems ノードを使用して、Visual Studio デバッガーで型を配列として解釈し、その個々の要素を表示します。 std::vector の視覚化は良い例です。

<Type Name="std::vector&lt;*&gt;">
  <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 の展開を使用した std::vector

ArrayItems ノードには次のものが必要です。

  • デバッガーが配列の長さを理解するための Size 式 (整数に評価する必要があります)。
  • 最初の要素を指す ValuePointer 式 (void*ではない要素型のポインターである必要があります)。

配列の下限の既定値は 0 です。 値をオーバーライドするには、LowerBound 要素を使用します。 Visual Studio に付属 .natvis ファイルには例があります。

手記

型自体 (CATLArrayなど) でこの演算子が許可されていない場合でも、[] 演算子 (vector[i]など) を、ArrayItemsを使用する任意の 1 次元配列視覚化と共に使用できます。

多次元配列を指定することもできます。 その場合、デバッガーは子要素を適切に表示するために少し多くの情報を必要とします。

<Type Name="Concurrency::array&lt;*,*&gt;">
  <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],... など

デバッガー ウィンドウでの 2 次元 Concurrency::array オブジェクトの外観を次に示します。

ArrayItems の展開を含む 2 次元配列 を持つ 2 次元配列

IndexListItems の展開

ArrayItems 展開は、配列要素がメモリ内で連続してレイアウトされている場合にのみ使用できます。 デバッガーは、ポインターをインクリメントするだけで次の要素に移動します。 値ノードに対してインデックスを操作する必要がある場合は、IndexListItems ノードを使用します。 IndexListItems ノードを使用した視覚化を次に示します。

<Type Name="Concurrency::multi_link_registry&lt;*&gt;">
  <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>

ArrayItemsIndexListItems の唯一の違いは、暗黙的な $i パラメーターを持つ i番目の 要素への完全な式を受け取る ValueNodeです。

手記

型自体 (CATLArrayなど) でこの演算子が許可されていない場合でも、[] 演算子 (vector[i]など) を、IndexListItemsを使用する任意の 1 次元配列視覚化と共に使用できます。

LinkedListItems の展開

視覚化された型がリンクリストを表す場合、デバッガーは LinkedListItems ノードを使用してその子を表示できます。 CAtlList 型の次の視覚化では、LinkedListItemsを使用します。

<Type Name="ATL::CAtlList&lt;*,*&gt;">
  <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_pNextm_element は、CAtlList クラスではなく、その CNode クラスのフィールドです。

ValueNode は空のままにすることも、this を使用して LinkedListItems ノード自体を参照することもできます。

CustomListItems の展開

CustomListItems 拡張を使用すると、ハッシュテーブルなどのデータ構造を走査するためのカスタム ロジックを記述できます。 CustomListItems を使用して、評価する必要があるすべてのものに対して C++ 式を使用できるデータ構造を視覚化しますが、ArrayItemsIndexListItems、または LinkedListItemsの金型には適していません。

Exec を使用すると、展開で定義されている変数とオブジェクトを使用して、CustomListItems 展開内でコードを実行できます。 Execでは、論理演算子、算術演算子、代入演算子を使用できます。 C++ の式エバリュエーターによってサポートされているデバッガー組み込み関数を除き、Exec を使用して関数を評価することはできません。

CAtlMap 用の次のビジュアライザーは、CustomListItems が適切な優れた例です。

<Type Name="ATL::CAtlMap&lt;*,*,*,*&gt;">
    <AlternativeType Name="ATL::CMapToInterface&lt;*,*,*&gt;"/>
    <AlternativeType Name="ATL::CMapToAutoPtr&lt;*,*,*&gt;"/>
    <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&lt;*&gt;">
  <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 ノードに似ています。 LeftPointerRightPointer、および ValueNode は、ツリー ノード クラスのコンテキストで評価されます。 ValueNode は空のままにするか、this を使用して TreeItems ノード自体を参照できます。

ExpandedItem の展開

ExpandedItem 要素は、基底クラスまたはデータ メンバーのプロパティを、視覚化された型の子であるかのように表示することで、集計された子ビューを生成します。 デバッガーは、指定された式を評価し、結果の子ノードを視覚化された型の子リストに追加します。

たとえば、スマート ポインターの種類 auto_ptr<vector<int>> 通常は次のように表示されます。

既定 auto_ptr<vector<int>> の既定の展開

ベクトルの値を確認するには、変数ウィンドウで 2 つのレベルをドリルダウンし、_Myptr メンバーを渡す必要があります。 ExpandedItem 要素を追加すると、階層から _Myptr 変数を削除し、ベクター要素を直接表示できます。

<Type Name="std::auto_ptr&lt;*&gt;">
  <DisplayString>auto_ptr {*_Myptr}</DisplayString>
  <Expand>
    <ExpandedItem>_Myptr</ExpandedItem>
  </Expand>
</Type>

auto_ptr<vector<int>> ExpandedItem の展開

次の例は、派生クラスの基底クラスからプロパティを集計する方法を示しています。 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&lt;*,*&gt;">
  <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>

Synthetic 要素の展開を含む Concurrency::Array

内在的拡張

式から呼び出すことができるカスタム組み込み関数。 <Intrinsic> 要素には、IDkmIntrinsicFunctionEvaluator140 インターフェイスを介して関数を実装するデバッガー コンポーネントを伴う必要があります。 カスタム組み込み関数の実装の詳細については、「NatVis カスタム組み込み関数を実装する」を参照してください。

<Type Name="std::vector&lt;*&gt;">
  <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 属性は、デバッガーの虫眼鏡アイコンの横にあるドロップダウン リストに表示するビジュアライザー名を定義します。 例えば:

    UIVisualizer メニューのショートカット メニュー

.natvis ファイルで定義されている各型は、それを表示できる UI ビジュアライザーを明示的に一覧表示する必要があります。 デバッガーは、型エントリ内のビジュアライザー参照を登録されたビジュアライザーと照合します。 たとえば、次の std::vector の型エントリは、前の例の UIVisualizer を参照します。

<Type Name="std::vector&lt;int,*&gt;">
  <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 要素では、ConditionIncludeView、および ExcludeView 属性を使用できます。

制限

Natvis のカスタマイズはクラスと構造体で動作しますが、typedef では機能しません。

Natvis では、プリミティブ型 (intboolなど) やプリミティブ型へのポインターのビジュアライザーはサポートされていません。 このシナリオでは、ユース ケースに適した 書式指定子 使用する方法があります。 たとえば、コードで double* mydoublearray を使用する場合は、デバッガーの ウォッチ ウィンドウで配列書式指定子 (最初の 100 個の要素を示す式 mydoublearray, [100]など) を使用できます。