Sdílet prostřednictvím


Vytváření vlastních zobrazení objektů C++ v ladicím programu pomocí architektury Natvis

Architektura Natvis platformy Visual Studio přizpůsobuje způsob, jakým se nativní typy zobrazují v oknech proměnných ladicího programu, jako jsou okna Lokální a okna Sledovat, a v Datumových tipech. Vizualizace Natvis vám můžou pomoct zajistit, aby byly typy, které vytváříte při ladění, viditelné.

Natvis nahrazuje soubor autoexp.dat v dřívějších verzích sady Visual Studio syntaxí XML, lepší diagnostikou, správou verzí a podporou více souborů.

Poznámka

Vlastní nastavení Natvis pracují se třídami a strukturami, ale ne s typedefy.

Vizualizace Natvis

Architekturu Natvis použijete k vytvoření pravidel vizualizace pro typy, které vytvoříte, aby je vývojáři mohli snadněji zobrazit během ladění.

Například následující obrázek ukazuje proměnnou typu Windows::UI::XAML::Controls::TextBox v okně ladicího programu bez použití vlastních vizualizací.

Textové pole výchozí vizualizace

Zvýrazněný řádek zobrazuje vlastnost Text třídy TextBox. Složitá hierarchie tříd znesnadňuje nalezení této vlastnosti. Ladicí program neví, jak interpretovat vlastní typ řetězce, takže nemůžete zobrazit řetězec uložený uvnitř textového pole.

TextBox vypadá v okně proměnných mnohem jednodušeji, když jsou použita vlastní pravidla vizualizéru Natvis. Důležité členy třídy se zobrazí společně a ladicí program zobrazí základní řetězcovou hodnotu vlastního typu řetězce.

TextBoxová data pomocí vizualizéru

Použití souborů .natvis v projektech C++

Natvis používá k určení pravidel vizualizace soubory .natvis. Soubor .natvis je soubor XML s příponou .natvis. Schéma Natvis je definováno v instalační složce <VS>\Xml\Schemas\1033\natvis.xsd.

Základní struktura souboru .natvis je jeden nebo více Type prvků představujících položky vizualizace. Plně kvalifikovaný název každého prvku Type je zadán v jeho Name atributu.

<?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 poskytuje některé soubory .natvis ve složce instalace <VS>\Common7\Packages\Debugger\Visualizers. Tyto soubory mají pravidla vizualizace pro mnoho běžných typů a můžou sloužit jako příklady pro psaní vizualizací pro nové typy.

Přidání souboru .natvis do projektu C++

Do libovolného projektu C++ můžete přidat soubor .natvis.

Přidání nového souboru .natvis:

  1. Vyberte uzel projektu C++ v Průzkumníku řešenía vyberte Project>Přidat novou položku, nebo klikněte pravým tlačítkem myši na projekt a vyberte Přidat>Nová položka.

    Pokud nevidíte všechny šablony položek, zvolte Zobrazit všechny šablony.

  2. V dialogovém okně Přidat novou položku vyberte Visual C++>Utility>vizualizační soubor ladicího programu (.natvis).

  3. Pojmenujte soubor a vyberte Přidat.

    Nový soubor se přidá do Průzkumníka řešenía otevře se v podokně dokumentů sady Visual Studio.

Ladicí program sady Visual Studio načte soubory .natvis v projektech C++ automaticky a ve výchozím nastavení je také zahrne do souboru .pdb při sestavení projektu. Pokud ladíte sestavenou aplikaci, ladicí program načte soubor .natvis ze souboru .pdb, i když nemáte projekt otevřený. Pokud nechcete, aby byl soubor .natvis zahrnutý v .pdb, můžete jej vyloučit ze sestaveného souboru .pdb.

Vyloučení souboru .natvis z.pdb:

  1. Vyberte soubor .natvis v Průzkumník řešenía vyberte ikonu Vlastnosti nebo klikněte pravým tlačítkem myši na soubor a vyberte Vlastnosti.

  2. Klikněte na šipku vedle Excluded From Build a vyberte Ano, a poté vyberte OK.

Poznámka

Pro ladění spustitelných projektů pomocí položek řešení přidejte všechny soubory .natvis, které nejsou v .pdb, protože neexistuje žádný projekt C++.

Poznámka

Pravidla Natvis načtená z .pdb se vztahují pouze na typy v modulech, na které .pdb odkazuje. Pokud má například Module1.pdb položku Natvis pro typ pojmenovaný Test, vztahuje se pouze na třídu Test v Module1.dll. Pokud jiný modul také definuje třídu s názvem Test, Module1.pdb položka Natvis se na ni nevztahuje.

Instalace a registrace souboru .natvis prostřednictvím balíčku VSIX:

Balíček VSIX může nainstalovat a zaregistrovat soubory .natvis. Bez ohledu na to, kde jsou nainstalovány, všechny registrované .natvis soubory jsou automaticky načteny během ladění.

  1. Do balíčku VSIX zahrňte soubor .natvis. Například pro následující soubor projektu:

    <?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. Zaregistrujte soubor .natvis v souboru 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>
    

Umístění souborů Natvis

Soubory .natvis můžete přidat do uživatelského adresáře nebo do systémového adresáře, pokud je chcete použít pro více projektů.

Soubory .natvis se vyhodnocují v následujícím pořadí:

  1. Všechny soubory .natvis, které jsou vloženy do .pdb během ladění, pokud v načteném projektu neexistuje soubor se stejným názvem.

  2. Všechny .natvis soubory načtené do projektu C++ nebo do řešení nejvyšší úrovně. Tato skupina zahrnuje všechny načtené projekty C++, včetně knihoven tříd, ale ne projektů v jiných jazycích.

  3. Všechny .natvis soubory nainstalované a registrované prostřednictvím balíčku VSIX.

  1. Adresář Natvis specifický pro uživatele (například %USERPROFILE%\Documents\Visual Studio 2022\Visualizers).
  1. Adresář Natvis specifický pro uživatele (například %USERPROFILE%\Documents\Visual Studio 2019\Visualizers).
  1. Systémový adresář Natvis (<Instalační složka sady Microsoft Visual Studio>\Common7\Packages\Debugger\Visualizers). Tento adresář obsahuje soubory .natvis, které jsou nainstalovány se sadou Visual Studio. Pokud máte oprávnění správce, můžete do tohoto adresáře přidat soubory.

Úprava souborů .natvis při ladění

Při ladění projektu můžete upravit soubor .natvis v integrovaném vývojovém prostředí (IDE). Otevřete soubor ve stejné instanci sady Visual Studio, pomocí které ladíte, upravte ho a uložte. Jakmile se soubor uloží, okna Watch a Locals se aktualizují, aby se změna projevila.

V řešení, které ladíte, můžete také přidat nebo odstranit soubory .natvis a Visual Studio přidá nebo odebere relevantní vizualizace.

Při ladění nemůžete aktualizovat soubory .natvis, které jsou vložené do souborů .pdb.

Pokud upravíte soubor .natvis mimo Visual Studio, změny se neprojeví automaticky. Chcete-li aktualizovat okna ladicího programu, můžete znovu vyhodnotit příkaz .natvisreload v Okamžitém okně . Změny se pak projeví bez restartování relace ladění.

Pomocí příkazu .natvisreload také upgradujte soubor .natvis na novější verzi. Například soubor .natvis může být vrácen do správy zdrojového kódu a chcete vyzvednout nedávné změny, které provedl někdo jiný.

Výrazy a formátování

Vizualizace Natvis používají výrazy jazyka C++ k určení datových položek, které se mají zobrazit. Kromě vylepšení a omezení výrazů jazyka C++ v ladicím nástroji, která jsou popsána v kontextový operátor (C++), mějte na paměti následující:

  • Výrazy Natvis se vyhodnocují v kontextu vizualizovaného objektu, nikoli v aktuálním zásobníkovém rámci. Například x ve výrazu Natvis odkazuje na pole s názvem x v vizualizovaném objektu, nikoli na místní proměnnou s názvem x v aktuální funkci. Ve výrazech Natvis nemáte přístup k místním proměnným, i když máte přístup k globálním proměnným.

  • Výrazy Natvis neumožňují vyhodnocení funkce ani vedlejší účinky. Volání funkcí a operátory přiřazení se ignorují. Protože intrinsické funkce debuggeru jsou bez vedlejších účinků, mohou být volně volány z jakéhokoli výrazu Natvis, přestože jiná volání funkcí jsou zakázána.

  • Chcete-li řídit způsob zobrazení výrazu, můžete použít libovolný specifikátor formátu popsaný v částce Specifikátory formátu v C++. Specifikátory formátu se ignorují, když se položka používá interně v rámci Natvis, například výraz Size v expanzi ArrayItems .

Poznámka

Vzhledem k tomu, že dokument Natvis je formátu XML, nemohou vaše výrazy přímo použít znak ampersand, větší než, menší než nebo operátory posunu. Tyto znaky je nutné escapovat jak v těle položky, tak v podmínkových výrazech. Například:
\<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\>

Zobrazení Natvis

Různá zobrazení Natvis můžete definovat tak, aby zobrazovala typy různými způsoby. Tady je například vizualizace std::vector, která definuje zjednodušené zobrazení s názvem simple. Prvky DisplayString a ArrayItems se zobrazují ve výchozím zobrazení a v zobrazení simple, zatímco položky [size] a [capacity] se v zobrazení simple nezobrazují.

<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>

V okně Sledování použijte specifikátor formátu ,zobrazení k zadání alternativního zobrazení. Jednoduché zobrazení se zobrazí jako vec,view(simple):

okno Okno sledování s jednoduchým zobrazením

Chyby Natvis

Když ladicí program narazí na chyby v položce vizualizace, ignoruje je. Buď zobrazí typ v nezpracované podobě, nebo vybere jinou vhodnou vizualizaci. Pomocí diagnostiky Natvis můžete zjistit, proč ladicí program ignoroval položku vizualizace, a zobrazit základní syntaxi a analyzovat chyby.

Zapnutí diagnostiky Natvis:

  • V části Tools>Options (nebo Debug>Options) >Debugging>Output Windownastavte Natvis diagnostické zprávy (C++ Pouze) na Chyba, Upozorněnínebo Podrobnéa poté vyberte OK.

Chyby se zobrazí v okně Výstup .

Referenční příručka pro syntaxi Natvis

Následující prvky a atributy lze použít v souboru Natvis.

AutoVisualizer prvek

Element AutoVisualizer je kořenovým uzlem souboru .natvis a obsahuje atribut oboru názvů xmlns:.

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
.
.
</AutoVisualizer>

Element AutoVisualizer může mít podřízené prvky typu, HResult, UIVisualizera CustomVisualizer.

Typ elementu

Základní Type vypadá jako v tomto příkladu:

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

Element Type určuje:

  1. Jaký typ vizualizace se má použít (atribut Name).

  2. Jak by měla vypadat hodnota objektu daného typu (prvek DisplayString).

  3. Jak by členové typu měli vypadat, když uživatel rozbalí typ v okně proměnné (uzel Expand).

Šablonované třídy

Atribut Name elementu Type přijímá hvězdičku * jako zástupný znak, který lze použít pro názvy tříd šablon.

V následujícím příkladu se používá stejná vizualizace, zda je objekt CAtlArray<int> nebo CAtlArray<float>. Pokud pro CAtlArray<float>existuje určitá položka vizualizace, má přednost před obecnou položkou.

<Type Name="ATL::CAtlArray&lt;*&gt;">
    <DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>

Parametry šablony v položce vizualizace můžete použít pomocí maker $T1, $T2 atd. Příklady těchto maker najdete v souborů .natvis dodávaná se sadou Visual Studio.

Porovnávání typů vizualizéru

Pokud se nepovede ověřit položku vizualizace, použije se další dostupná vizualizace.

Zděděný atribut

Volitelný atribut Inheritable určuje, zda se vizualizace vztahuje pouze na základní typ, nebo na základní typ a všechny odvozené typy. Výchozí hodnota Inheritable je true.

V následujícím příkladu se vizualizace vztahuje pouze na typ BaseClass:

<Type Name="Namespace::BaseClass" Inheritable="false">
    <DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>

Atribut Priorita

Volitelný atribut Priority určuje pořadí, ve kterém se mají použít alternativní definice, pokud se definici nepodaří analyzovat. Možné hodnoty Priority jsou: Low, MediumLow,Medium, MediumHigha High. Výchozí hodnota je Medium. Atribut Priority rozlišuje pouze priority ve stejném souboru .natvis.

Následující příklad nejprve analyzuje položku, která odpovídá hodnotě STL 2015. Pokud se to nepodaří analyzovat, použije alternativní položku pro verzi 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>

Volitelný atribut

Atribut Optional můžete umístit na libovolný uzel. Pokud se dílčí výraz uvnitř volitelného uzlu nepodaří analyzovat, ladicí program tento uzel ignoruje, ale použije zbytek pravidel Type. V následujícím typu [State] není volitelný, ale [Exception] je nepovinný. Pokud má MyNamespace::MyClass pole s názvem _M_exceptionHolder, zobrazí se uzel [State] i uzel [Exception], ale pokud neexistuje žádné pole _M_exceptionHolder, zobrazí se pouze uzel [State].

<Type Name="MyNamespace::MyClass">
    <Expand>
      <Item Name="[State]">_M_State</Item>
      <Item Name="[Exception]" Optional="true">_M_exceptionHolder</Item>
    </Expand>
</Type>

Atribut podmínky

Volitelný atribut Condition je k dispozici pro mnoho prvků vizualizace a určuje, kdy se má použít pravidlo vizualizace. Pokud se výraz uvnitř atributu podmínky přeloží na false, pravidlo vizualizace se nepoužije. Pokud se vyhodnotí jako truenebo neexistuje žádný atribut Condition, vizualizace se použije. Tento atribut můžete použít pro logiku if-else v položkách vizualizace.

Například následující vizualizace obsahuje dva prvky DisplayString pro typ inteligentního ukazatele. Když je _Myptr člen prázdný, podmínka prvního prvku DisplayString se přeloží na true, aby se formulář zobrazil. Pokud _Myptr člen není prázdný, podmínka se vyhodnotí jako falsea druhý prvek DisplayString zobrazí.

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

Atributy IncludeView a ExcludeView

Atributy IncludeView a ExcludeView určují prvky, které se mají zobrazit nebo nezobrazují v konkrétních zobrazeních. Například v následující specifikaci Natvis std::vectorzobrazení simple nezobrazuje položky [size] a [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>

U typů a jednotlivých členů můžete použít atributy IncludeView a ExcludeView.

Součást verze

Element Version vymezuje položku vizualizace na konkrétní modul a verzi. Prvek Version pomáhá vyhnout se kolizím názvů, snižuje neúmyslné neshody a umožňuje různé vizualizace pro různé verze typů.

Pokud společný hlavičkový soubor, který používá různé moduly, definuje typ, zobrazí se vizualizace s verzí pouze v případě, že je typ v zadané verzi modulu.

V následujícím příkladu je vizualizace použitelná pouze pro typ DirectUI::Border nalezený v Windows.UI.Xaml.dll verze 1.0 až 1.5.

<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>

Nepotřebujete Min ani Max. Jedná se o volitelné atributy. Nepodporují se žádné zástupné znaky.

Atribut Name je ve formátu název_souboru.ext, například hello.exe nebo some.dll. Nejsou povoleny žádné názvy cest.

DisplayString prvek

Prvek DisplayString určuje řetězec, který se má zobrazit jako hodnota proměnné. Přijímá libovolné řetězce smíšené s výrazy. Vše uvnitř složených závorek se interpretuje jako výraz. Například následující DisplayString položka:

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

Znamená, že proměnné typu CPoint jsou zobrazeny jako na tomto obrázku:

Použijte prvek DisplayString

Ve výrazu DisplayString jsou x a y, které jsou členy CPoint, umístěné v složených závorkách, takže jejich hodnoty se vyhodnotí. Příklad také ukazuje, jak můžete eskapovat složené závorky pomocí dvou složených závorek ({{ nebo }}).

Poznámka

Prvek DisplayString je jediný prvek, který přijímá libovolné řetězce a syntaxi složených závorek. Všechny ostatní prvky vizualizace přijímají pouze výrazy, které ladicí program může vyhodnotit.

StringView – element

Element StringView definuje hodnotu, kterou ladicí program může odeslat do integrovaného vizualizéru textu. Například vzhledem k následující vizualizaci pro typ ATL::CStringT:

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

Objekt CStringT se zobrazí v okně proměnné, jako je tento příklad:

CStringT DisplayString element

Přidání StringView elementu říká ladicímu programu, že může zobrazit hodnotu jako textovou vizualizaci.

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

Během ladění můžete vybrat ikonu lupy vedle proměnné a poté vybrat Vizualizér textu, abyste zobrazili řetězec, na který odkazuje m_pszData.

data CStringT s vizualizérem StringView

Výraz {m_pszData,su} obsahuje specifikátor formátu C++ su, aby se hodnota zobrazila jako řetězec Unicode. Další informace naleznete v tématu Specifikátory formátu v jazyce C++.

Rozbalit prvek

Volitelný Expand uzel přizpůsobí podřízené položky vizualizovaného typu při rozbalení typu v okně proměnné. Uzel Expand přijímá seznam podřízených uzlů, které definují podřízené prvky.

  • Pokud v položce vizualizace není zadaný uzel Expand, použijí podřízené položky výchozí pravidla rozšíření.

  • Pokud je zadaný uzel Expand bez podřízených uzlů, typ není v oknech ladicího programu rozbalitelný.

Rozšíření položky

Prvek Item je nejzásadnější a nejběžnější prvek v Expand uzlu. Item definuje jeden podřízený prvek. Například třída CRect s poli top, left, righta bottom má následující položku vizualizace:

<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>

V okně ladicího programu vypadá typ CRect takto:

CRect s rozšířením prvku Item

Ladicí program vyhodnotí výrazy zadané v prvcích Width a Height a zobrazí hodnoty ve sloupci Hodnota v okně s proměnnými.

Ladicí program automaticky vytvoří uzel [Surový pohled] pro každé vlastní rozšíření. Předchozí snímek obrazovky zobrazuje uzel [Nezpracované zobrazení] v rozbaleném stavu, aby bylo zřejmé, jak se výchozí nezpracované zobrazení objektu liší od jeho vizualizace pomocí Natvis. Výchozí rozšíření vytvoří podstrom základní třídy a vypíše všechny datové členy základní třídy jako podřízené položky.

Poznámka

Pokud výraz prvku položky odkazuje na komplexní typ, Item uzel je rozbalitelný.

Rozšíření položek Array

Použijte uzel ArrayItems k tomu, aby ladicí program sady Visual Studio interpretovala typ jako pole a zobrazila jeho jednotlivé prvky. Příklad vizualizace pro 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 zobrazí jednotlivé prvky při rozbalení v okně proměnné:

rozšíření std::vector pomocí rozšíření ArrayItems

Uzel ArrayItems musí mít:

  • Výraz Size (který musí být vyhodnocen jako celé číslo), aby ladicí program porozuměl délce pole.
  • Výraz ValuePointer, který odkazuje na první prvek (což musí být ukazatel typu prvku, který není void*).

Výchozí hodnota dolní hranice pole je 0. K přepsání hodnoty použijte prvek LowerBound. Soubory .natvis dodávané se sadou Visual Studio obsahují příklady.

Poznámka

Můžete použít operátor [], například vector[i], s libovolnou jednorozměrnou maticovou vizualizací, která používá ArrayItems, i když samotný typ (například CATLArray) neumožňuje tento operátor.

Můžete také zadat vícerozměrná pole. V takovém případě ladicí program potřebuje k správnému zobrazení podřízených prvků o něco více informací:

<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 určuje, jestli je pole v řádkovém nebo sloupcovém uspořádání.
  • Rank určuje pořadí pole.
  • Element Size přijímá implicitní $i parametr, který nahradí indexem dimenze, aby zjistil délku pole v dané dimenzi.
    • V předchozím příkladu by výraz _M_extent.M_base[0] měl dát délku 0. dimenze, _M_extent._M_base[1] první a tak dále.
  • LowerBound určuje dolní mez každé dimenze pole. U multidimenzionálních polí můžete zadat výraz, který používá implicitní $i parametr. Parametr $i bude nahrazen indexem dimenze, který najde dolní mez pole v této dimenzi.
    • V předchozím příkladu budou všechny dimenze začínat na 0. Pokud jste však měli ($i == 1) ? 1000 : 100 jako dolní mez, začne 0. dimenze na 100 a první dimenze začne na 1000.
      • , například [100, 1000], [100, 1001], [100, 1002], ... [101, 1000], [101, 1001],...

V okně ladění vypadá dvojrozměrný objekt Concurrency::array takto:

dvojrozměrné pole s rozšířením ArrayItems

Rozšíření seznamu položek indexu

Rozšíření ArrayItems lze použít pouze v případě, že jsou prvky pole rozloženy souvisle v paměti. Ladicí program se dostane k dalšímu prvku pouhým zvýšením pointeru. Pokud potřebujete manipulovat s indexem uzlu hodnoty, použijte IndexListItems uzly. Tady je vizualizace s IndexListItems uzlem:

<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>

Jediným rozdílem mezi ArrayItems a IndexListItems je ValueNode, který očekává úplný výraz pro i-týprvek s implicitním parametrem $i.

Poznámka

Můžete použít operátor [], například vector[i], s libovolnou jednorozměrnou maticovou vizualizací, která používá IndexListItems, i když samotný typ (například CATLArray) neumožňuje tento operátor.

Rozšíření položek LinkedList

Pokud vizualizovaný typ představuje propojený seznam, může ladicí program zobrazit podřízené položky pomocí uzlu LinkedListItems. Následující vizualizace pro typ CAtlList používá 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>

Prvek Size odkazuje na délku seznamu. HeadPointer odkazuje na první prvek, NextPointer odkazuje na další prvek a ValueNode odkazuje na hodnotu položky.

Ladicí program vyhodnotí výrazy NextPointer a ValueNode v kontextu elementu LinkedListItems node, nikoli nadřazeného typu seznamu. V předchozím příkladu má CAtlList třídu CNode (nalezenou v atlcoll.h), která je uzlem propojeného seznamu. m_pNext a m_element jsou pole této třídy CNode, nikoli třídy CAtlList.

ValueNode může být ponechána prázdná nebo pomocí this odkazovat na samotný uzel LinkedListItems.

Rozšíření CustomListItems

Rozšíření CustomListItems umožňuje napsat vlastní logiku pro procházení datové struktury, jako je například hashtable. Pomocí CustomListItems můžete vizualizovat datové struktury, které mohou používat výrazy jazyka C++ pro veškeré potřebné vyhodnocení, ale ne zcela odpovídají formátům ArrayItems, IndexListItemsnebo LinkedListItems.

Pomocí Exec můžete spustit kód uvnitř rozšíření CustomListItems pomocí proměnných a objektů definovaných v rozšíření. Můžete použít logické operátory, aritmetické operátory a operátory přiřazení s Exec. Nemůžete použít Exec k vyhodnocení funkcí, s výjimkou vnitřních funkcí ladicího programu podporované vyhodnocovačem výrazů jazyka C++.

Následující vizualizér pro CAtlMap je skvělým příkladem, kde je vhodný 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>

Rozšíření TreeItems

Pokud zobrazený typ představuje strom, ladicí program může strom procházet a zobrazit jeho potomky pomocí uzlu TreeItems. Tady je vizualizace typu std::map pomocí TreeItems uzlu:

<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>

Syntaxe se podobá uzlu LinkedListItems. LeftPointer, RightPointera ValueNode se vyhodnocují v kontextu třídy uzlu stromu. ValueNode může být ponechána prázdná nebo pomocí this odkazovat na samotný uzel TreeItems.

Rozšíření položky ExpandedItem

Element ExpandedItem generuje agregované podřízené zobrazení tím, že zobrazuje vlastnosti základních tříd nebo datových členů, jako by byly podřízenými prvky vizualizovaného typu. Debugger vyhodnotí zadaný výraz a připojí uzly potomků výsledku do seznamu uzlů potomků vizualizovaného typu.

Například typ inteligentního ukazatele auto_ptr<vector<int>> obvykle zobrazuje takto:

auto_ptr<vector<>> výchozí rozšíření

Pokud chcete zobrazit hodnoty vektoru, musíte se ponořit o dvě úrovně hlouběji v okně proměnné a projít přes prvek _Myptr. Přidáním ExpandedItem elementu můžete eliminovat _Myptr proměnnou z hierarchie a přímo zobrazit vektorové prvky:

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

auto_ptr<rozšíření< ExpandedItem>>rozšíření

Následující příklad ukazuje, jak agregovat vlastnosti ze základní třídy v odvozené třídě. Předpokládejme, že třída CPanel je odvozena od CFrameworkElement. Namísto opakování vlastností, které pocházejí ze základní CFrameworkElement třídy, připojí vizualizace ExpandedItem uzlu tyto vlastnosti do podřízeného seznamu třídy CPanel.

<Type Name="CPanel">
  <DisplayString>{{Name = {*(m_pstrName)}}}</DisplayString>
  <Expand>
    <Item Name="IsItemsHost">(bool)m_bItemsHost</Item>
    <ExpandedItem>*(CFrameworkElement*)this,nd</ExpandedItem>
  </Expand>
</Type>

Specifikátory formátu a, které vypnou sladění vizualizace pro odvozenou třídu, jsou zde nezbytné. Jinak by výraz *(CFrameworkElement*)this způsoboval, že se vizualizace CPanel aplikovala znovu, protože výchozí pravidla pro porovnávání typů vizualizací ji považují za nejvhodnější. Pomocí specifikátoru nd formátu instruujte ladicí program, aby používal vizualizaci základní třídy, nebo výchozí rozšíření, pokud základní třída nemá žádnou vizualizaci.

Rozšíření syntetických položek

I když prvek ExpandedItem poskytuje ploché zobrazení dat odstraněním hierarchií, Synthetic uzel dělá opačně. Umožňuje vytvořit umělý podřízený prvek, který nevznikl jako výsledek výrazu. Umělý prvek může mít vlastní podřízené prvky. V následujícím příkladu vizualizace pro typ Concurrency::array používá uzel Synthetic k zobrazení diagnostické zprávy uživateli:

<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>

Concurrency::Array s rozšířením syntetických prvků

Vnitřní rozšíření

Vlastní vnitřní funkce, kterou lze volat z výrazu. Prvek <Intrinsic> musí být doprovázen komponentou ladicího programu, která implementuje funkci prostřednictvím rozhraní IDkmIntrinsicFunctionEvaluator140. Další informace o implementaci vlastní vnitřní funkce naleznete v tématu Implementace vlastní vnitřní funkce 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 prvek

Element HResult umožňuje přizpůsobit informace zobrazené pro HRESULT v oknech ladicího programu. Prvek HRValue musí obsahovat 32bitovou hodnotu HRESULT, která se má vlastně upravit. Prvek HRDescription obsahuje informace k zobrazení v okně ladicího programu.


<HResult Name="MY_E_COLLECTION_NOELEMENTS">
  <HRValue>0xABC0123</HRValue>
  <HRDescription>No elements in the collection.</HRDescription>
</HResult>

UIVisualizer — prvek

Prvek UIVisualizer zaregistruje zásuvný modul grafického vizualizéru pro ladicí program. Grafický vizualizér vytvoří dialogové okno nebo jiné rozhraní, které zobrazuje proměnnou nebo objekt způsobem konzistentním s jeho datovým typem. Plug-in vizualizéru musí být vytvořen jako VSPackagea musí nabízet službu, kterou může ladicí program využívat. Soubor .natvis obsahuje registrační informace pro modul plug-in, například jeho název, globálně jedinečný identifikátor (GUID) vystavené služby a typy, které může vizualizovat.

Tady je příklad elementu 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>
  • Dvojice atributů ServiceId - Id identifikuje UIVisualizer. ServiceId je identifikátor GUID služby, která balíček vizualizéru zveřejňuje. Id je jedinečný identifikátor, který rozlišuje vizualizéry, pokud služba poskytuje více než jeden. V předchozím příkladu poskytuje stejná služba vizualizéru dva vizualizéry.

  • Atribut MenuName definuje název vizualizéru, který se zobrazí v rozevíracím seznamu vedle ikony lupy v ladicím programu. Například:

    místní nabídka menu UIVisualizer

Každý typ definovaný v souboru .natvis musí explicitně zobrazit všechny vizualizéry uživatelského rozhraní, které ho mohou zobrazit. Ladicí program porovnává odkazy vizualizeru v položkách typu s registrovanými vizualizéry. Například následující položka typu pro std::vector odkazuje na UIVisualizer v předchozím příkladu.

<Type Name="std::vector&lt;int,*&gt;">
  <UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
</Type>

Příklad můžete zobrazit v rozšíření Image Watch, které se používá k zobrazení rastrových obrázků v paměti.

Prvek CustomVisualizer

CustomVisualizer je bod rozšiřitelnosti, který určuje rozšíření VSIX, které napíšete pro řízení vizualizací v editoru Visual Studio Code. Další informace o psaní rozšíření VSIX naleznete v Visual Studio SDK.

Je mnohem více práce napsat vlastní vizualizér než definice Natvis XML, ale nemáte omezení ohledně toho, co Natvis dělá nebo nepodporuje. Vlastní vizualizéry mají přístup k úplné sadě rozhraní API rozšiřitelnosti ladicího programu, která můžou dotazovat a upravovat proces ladění nebo komunikovat s jinými částmi sady Visual Studio.

U prvků Condition můžete použít atributy IncludeView, ExcludeViewa CustomVisualizer.

Omezení

Vlastní nastavení Natvis pracují se třídami a strukturami, ale ne s typedefy.

Natvis nepodporuje vizualizéry pro primitivní typy (například int, bool) nebo ukazatele na primitivní typy. V tomto scénáři je jednou z možností použít specifikátor formátu vhodný pro váš případ použití. Pokud například ve svém kódu použijete double* mydoublearray, můžete použít specifikátor formátu pole v okně Kukátko watch, například výraz mydoublearray, [100], který zobrazuje prvních 100 prvků.