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

Architektura Natvis sady Visual Studio přizpůsobí způsob, jakým se nativní typy zobrazují v oknech proměnných ladicího programu, například v oknech Locals a Watch a Data Tipy. 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í s třídami a strukturami, ale ne typedefs.

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 znázorňuje proměnnou typu Windows::UI::XAML::Controls::TextBox v okně ladicího programu bez použití vlastních vizualizací.

Výchozí vizualizace TextBoxu

Zvýrazněný řádek zobrazuje Text vlastnost TextBox třídy. 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 Totéž vypadá mnohem jednodušší v okně proměnné při použití vlastních pravidel 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.

Data TextBoxu pomocí vizualizéru

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

Natvis používá soubory .natvis k určení pravidel vizualizace. Soubor .natvis je soubor XML s příponou .natvis . Schéma Natvis je definováno ve <složce> Instalace 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 Type prvku 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ík řešení a vyberte Přidat novou položku projektu>nebo klikněte pravým tlačítkem myši na projekt a vyberte Přidat>novou položku.

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

  2. V dialogovém okně Přidat novou položku vyberte soubor vizualizace visual C++>Utility>Debugger (.natvis).

  3. Pojmenujte soubor a vyberte Přidat.

    Nový soubor se přidá do Průzkumník ř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ž projekt nemáte otevřený. Pokud nechcete , aby byl soubor .natvis zahrnutý v souboru .pdb, můžete ho vyloučit z vytvořeného souboru .pdb .

Vyloučení souboru .natvis z souboru .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. Rozevírací seznam se šipkou vedle možnosti Vyloučeno z sestavení a vyberte Ano a pak vyberte OK.

Poznámka:

Pro ladění spustitelných projektů použijte položky řešení k přidání všech souborů .natvis , které nejsou v souboru .pdb, protože není k dispozici žádný projekt C++.

Poznámka:

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

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

Balíček VSIX může instalovat a registrovat soubory .natvis . Bez ohledu na to, kde jsou nainstalované, se během ladění automaticky vyberou všechny registrované soubory .natvis .

  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 vložené do souboru .pdb , který ladíte, pokud v načteném projektu neexistuje soubor se stejným názvem.

  2. Všechny soubory .natvis , které jsou v načteném projektu C++ nebo ř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 soubory .natvis 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. Adresář Natvis pro celý systém (<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ží, aktualizace windows Kukátko a Místní hodnoty tak, aby odrážely změnu.

Soubory .natvis můžete také přidat nebo odstranit v řešení, které ladíte, 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 příkazovém okně. Změny se pak projeví bez restartování relace ladění.

K upgradu souboru .natvisreload na novější verzi použijte také příkaz .natvisload. 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 programu, které jsou popsány v kontextovém operátoru (C++), mějte na paměti následující:

  • Výrazy Natvis se vyhodnocují v kontextu vizualizovaného objektu, nikoli v aktuálním rámečku zásobníku. Například x ve výrazu Natvis odkazuje na pole pojmenované 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í. Vzhledem k tomu, že vnitřní funkce ladicího programu jsou bez vedlejšího efektu, mohou být volně volány z jakéhokoli výrazu Natvis, i když jsou jiná volání funkcí zakázána.

  • Pokud chcete určit, jak se výraz zobrazí, můžete použít libovolný specifikátor formátu popsaný ve specifikátorech formátu v jazyce C++. Specifikátory formátu se ignorují, když se položka interně používá v Natvis, například Size výraz v rozšíření ArrayItems.

Poznámka:

Vzhledem k tomu, že dokument Natvis je XML, nemohou výrazy přímo používat ampersand, větší než, menší než nebo operátory shift. Tyto znaky je nutné u řídicích znaků v textu položky i v příkazech podmínky. Pří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 se ArrayItems zobrazují ve výchozím zobrazení a simple v zobrazení, zatímco [size] položky se [capacity] v simple zobrazení 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ě Kukátko zadejte alternativní zobrazení pomocí specifikátoru formátu zobrazení. Jednoduché zobrazení se zobrazí jako vec,view(simple):

Okno kukátka 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 Možnosti nástrojů>(nebo Možnosti ladění>) >Okno výstupu ladění>nastavte diagnostické zprávy Natvis (pouze C++) na hodnotu Chyba, Upozornění nebo Podrobné a pak vyberte OK.

Chyby se zobrazí v okně Výstup .

Odkaz na syntaxi Natvis

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

Element AutoVisualizer

Element AutoVisualizer je kořenový uzel 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 obsahovat podřízené objekty Type, HResult, UIVisualizer a CustomVisualizer .

Element Type

Základní Type příklad vypadá takto:

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

Prvek Type určuje:

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

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

  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 šablon třídy.

V následujícím příkladu se stejná vizualizace používá bez ohledu na to, zda je objekt nebo CAtlArray<int> .CAtlArray<float> Pokud existuje pro konkrétní CAtlArray<float>položku 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 odkazovat pomocí maker $T 1, $T 2 atd. Příklady těchto maker najdete v souborech .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ý Inheritable atribut určuje, zda se vizualizace vztahuje pouze na základní typ, nebo na základní typ a všechny odvozené typy. Výchozí hodnota atributu Inheritable je true.

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

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

Atribut Priority

Volitelný Priority atribut určuje pořadí, ve kterém se mají použít alternativní definice, pokud se definice nepodaří analyzovat. Možné hodnoty Priority jsou: Low, , MediumLowMedium, 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 můžete umístit Optional na libovolný uzel. Pokud se dílčí výraz uvnitř volitelného uzlu nepodaří analyzovat, ladicí program tento uzel ignoruje, ale použije zbytek Type pravidel. V následujícím typu [State] není volitelný, ale [Exception] je nepovinný. Pokud MyNamespace::MyClass má pole s názvem _M_exceptionHolder, [State] zobrazí se uzel i [Exception] uzel, ale pokud neexistuje žádné _M_exceptionHolder pole, zobrazí se pouze [State] uzel.

<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ý Condition atribut 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ý Condition atribut, 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 DisplayString prvky pro typ inteligentního ukazatele. _Myptr Když je člen prázdný, podmínka prvního DisplayString prvku se přeloží na true, aby se formulář zobrazil. _Myptr Pokud člen není prázdný, podmínka se vyhodnotí jako falsea druhý DisplayString prvek se 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

ExcludeView Atributy IncludeView určují prvky, které se mají zobrazit nebo nezobrazují v konkrétních zobrazeních. Například v následující specifikaci std::vectorNatvis zobrazení simple nezobrazuje [size] a [capacity] položky.

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

Můžete použít IncludeView atributy pro ExcludeView typy a jednotlivé členy.

Prvek verze

Element Version definuje položku vizualizace na konkrétní modul a verzi. Tento Version prvek 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 DirectUI::Border typ nalezený ve Windows.UI.Xaml.dll verzi 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 obojí Min a Max. Jedná se o volitelné atributy. Nepodporují se žádné zástupné znaky.

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

DisplayString – element

Element 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 se zobrazují jako na tomto obrázku:

Použití elementu DisplayString

Ve výrazu DisplayStringx a y, které jsou členy CPoint, jsou uvnitř složených závorek, takže jejich hodnoty jsou vyhodnoceny. Příklad také ukazuje, jak můžete utéct složenou závorku pomocí dvojitých složených závorek ( {{ nebo }} ).

Poznámka:

Element DisplayString je jediný prvek, který přijímá libovolné řetězce a složené závorky syntaxe. 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 ATL::CStringT typ:

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

Objekt CStringT se zobrazí v okně proměnné jako v tomto příkladu:

CStringT DisplayString – element

Přidání elementu StringView ří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 pak vybrat Vizualizér textu a zobrazit řetězec, na který m_pszData odkazuje.

Data CStringT s vizualizérem StringView

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

Expand – element

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.

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

  • Expand Pokud je uzel zadaný 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 CRect třída 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 jako v tomto příkladu CRect :

CRect s rozšířením elementu Item

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

Ladicí program automaticky vytvoří uzel [Nezpracované zobrazení] pro každé vlastní rozšíření. Předchozí snímek obrazovky zobrazuje rozbalený uzel [Nezpracované zobrazení] a ukazuje, jak se výchozí nezpracované zobrazení objektu liší od vizualizace 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, uzel Item samotný je rozbalitelný.

Rozšíření ArrayItems

ArrayItems Pomocí uzlu můžete ladicí program sady Visual Studio interpretovat typ jako pole a zobrazit jeho jednotlivé prvky. std::vector Vizualizace je dobrým příkladem:

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

Při rozbalení v okně proměnné se std::vector zobrazí jeho jednotlivé prvky:

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

Uzel ArrayItems musí mít:

  • Výraz Size (který musí být vyhodnocen jako celé číslo) pro ladicí program, aby 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 LowerBound prvek. Soubory .natvis dodávané se sadou Visual Studio obsahují příklady.

Poznámka:

Operátor můžete použít [] například vector[i]s libovolnou vizualizací jednorozměrného pole, která používá ArrayItems, i když samotný typ (například CATLArray) tento operátor nepovoluje.

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 pořadí hlavního řádku nebo hlavního sloupce.
  • Rank určuje pořadí pole.
  • Element Size přijímá implicitní $i parametr, který nahradí indexem dimenze, aby zjistil délku pole v této 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.
  • Určuje LowerBound 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, aby našel dolní mez pole v dané dimenzi.
    • V předchozím příkladu budou všechny dimenze začínat na 0. Pokud byste však měli ($i == 1) ? 1000 : 100 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ě ladicího programu vypadá dvojrozměrný Concurrency::array objekt:

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

Rozšíření IndexListItems

Rozšíření lze použít ArrayItems pouze v případě, že jsou prvky pole rozloženy souvisle v paměti. Ladicí program se dostane k dalšímu prvku jednoduchým zvýšením ukazatele. 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ý rozdíl mezi a je , který očekává úplný výraz na ith element s implicitní $i parametr.ValueNodeIndexListItemsArrayItems

Poznámka:

Operátor můžete použít [] například vector[i]s libovolnou vizualizací jednorozměrného pole, která používá IndexListItems, i když samotný typ (například CATLArray) tento operátor nepovoluje.

Rozšíření LinkedListItems

Pokud vizualizovaný typ představuje propojený seznam, může ladicí program zobrazit podřízené položky pomocí LinkedListItems uzlu. Následující vizualizace pro CAtlList typ 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í NextPointer výrazy a ValueNode výrazy v kontextu LinkedListItems prvku uzlu, nikoli nadřazeného typu seznamu. V předchozím příkladu CAtlListCNode třídu (nalezenou v atlcoll.h) , která je uzlem propojeného seznamu. m_pNext a m_element jsou pole této CNode třídy, nikoli CAtlList třídy.

ValueNode může být ponechána prázdná nebo se používá this k odkazování na LinkedListItems samotný uzel.

Rozšíření CustomListItems

Rozšíření CustomListItems umožňuje napsat vlastní logiku pro procházení datové struktury, jako je například hashtable. Umožňuje CustomListItems vizualizovat datové struktury, které můžou používat výrazy jazyka C++ pro všechno, co potřebujete k vyhodnocení, ale nevejde se do formy pro ArrayItems, IndexListItemsnebo LinkedListItems.

Můžete použít Exec ke spuštění kódu uvnitř CustomListItems rozšíření 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ých vyhodnocovačem výrazů jazyka C++.

Následující vizualizér CAtlMap je skvělým příkladem, kde CustomListItems je to vhodné.

<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 vizualizovaný typ představuje strom, ladicí program může strom procházet a zobrazit jeho podřízené položky pomocí TreeItems uzlu. 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 je podobná LinkedListItems uzlu. LeftPointer, RightPointera ValueNode jsou vyhodnoceny v kontextu třídy uzlu stromu. ValueNode může být ponechána prázdná nebo použít this k odkazování na TreeItems samotný uzel.

Rozšíření ExpandedItem

Element ExpandedItem generuje agregované podřízené zobrazení zobrazení zobrazením vlastností základních tříd nebo datových členů, jako by šlo o podřízené prvky vizualizovaného typu. Ladicí program vyhodnotí zadaný výraz a připojí podřízené uzly výsledku do podřízeného seznamu vizualizovaného typu.

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

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

Pokud chcete zobrazit hodnoty vektoru, musíte přejít k podrobnostem o dvou úrovních v okně proměnné a procházet členem _Myptr . Přidáním elementu _Myptr můžete eliminovat proměnnou ExpandedItem 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 vektor<int>> 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 CPanel třída je odvozena od CFrameworkElement. Místo opakování vlastností, které pocházejí ze základní CFrameworkElement třídy, ExpandedItem připojí vizualizace uzlu tyto vlastnosti do podřízeného CPanel seznamu třídy.

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

Zde je nezbytný specifikátor formátu nd , který vypne vizualizaci odpovídající odvozené třídě. Jinak by výraz *(CFrameworkElement*)this způsobil CPanel opětovné použití vizualizace, protože výchozí pravidla párování typů vizualizací považují za nejvhodnější. Specifikátor formátu nd použijte k pokynu ladicímu programu, 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

ExpandedItem I když prvek poskytuje ploché zobrazení dat odstraněním hierarchií, Synthetic uzel dělá opak. Umožňuje vytvořit umělý podřízený prvek, který není výsledkem výrazu. Umělý prvek může mít vlastní podřízené prvky. V následujícím příkladu vizualizace pro Concurrency::array typ používá Synthetic uzel 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ého prvku

Instrinsic expand

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.

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

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á přizpůsobit. Element HRDescription obsahuje informace, které se mají zobrazit v okně ladicího programu.


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

UIVisualizer – element

Prvek UIVisualizer zaregistruje modul plug-in grafického vizualizéru s ladicím programem. Grafický vizualizér vytvoří dialogové okno nebo jiné rozhraní, které zobrazuje proměnnou nebo objekt způsobem konzistentním s jeho datovým typem. Modul plug-in vizualizéru musí být vytvořený jako balíček VSPackage a musí vystavit službu, kterou může ladicí program využívat. Soubor .natvis obsahuje informace o registraci modulu plug-in, jako je 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>
  • Pár ServiceId - Id atributů identifikuje UIVisualizerhodnotu . Jedná se ServiceId o 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. Příklad:

    Místní nabídka nabídky 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 odpovídá odkazům vizualizéru v položkách typu s registrovanými vizualizéry. Například následující položka typu pro std::vector odkazy UIVisualizer v předchozím příkladu.

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

Můžete vidět příklad UIVisualizer rozšíření Image Watch použité k zobrazení rastrových obrázků v paměti.

CustomVisualizer – element

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 najdete v sadě 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 elementů můžete použít Conditionatributy , IncludeViewa ExcludeView atributy.CustomVisualizer

Omezení

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

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