Dela via


Skapa anpassade vyer av C++-objekt i felsökningsprogrammet med hjälp av Natvis-ramverket

Visual Studio Natvis-ramverket anpassar hur inbyggda typer visas i felsökningsvariabelfönster, till exempel Locals och Watch-fönster och i DataTips. Natvis-visualiseringar kan hjälpa dig att göra de typer som du skapar mer synliga under felsökningen.

Natvis ersätter den autoexp.dat filen i tidigare versioner av Visual Studio med XML-syntax, bättre diagnostik, versionshantering och stöd för flera filer.

Not

Natvis-anpassningar fungerar med klasser och strukturer, men inte med typdefinieringar.

Natvis-visualiseringar

Du använder Natvis-ramverket för att skapa visualiseringsregler för de typer du skapar, så att utvecklare enklare kan se dem under felsökningen.

Följande bild visar till exempel en variabel av typen Windows::UI::XAML::Controls::TextBox i ett felsökningsfönster utan att några anpassade visualiseringar tillämpas.

Standardvisualisering

Den markerade raden visar egenskapen Text för klassen TextBox. Den komplexa klasshierarkin gör det svårt att hitta den här egenskapen. Felsökaren vet inte hur den anpassade strängtypen ska tolkas, så du kan inte se strängen i textrutan.

Samma TextBox ser mycket enklare ut i variabelfönstret när natvis anpassade visualiseringsregler tillämpas. De viktiga medlemmarna i klassen visas tillsammans och felsökningsprogrammet visar det underliggande strängvärdet för den anpassade strängtypen.

TextBox-data med visualiserare

Använda .natvis-filer i C++-projekt

Natvis använder .natvis--filer för att ange visualiseringsregler. En .natvis-fil är en XML-fil med ett .natvis--tillägg. Natvis-schemat definieras i <VS-installationsmappen>\Xml\Schemas\1033\natvis.xsd.

Den grundläggande strukturen för en .natvis--fil är ett eller flera Type element som representerar visualiseringsposter. Det fullständigt kvalificerade namnet på varje Type-element anges i dess Name-attribut.

<?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 tillhandahåller några .natvis--filer i <VS-installationsmappens>\Common7\Packages\Debugger\Visualizers. Dessa filer har visualiseringsregler för många vanliga typer och kan fungera som exempel för att skriva visualiseringar för nya typer.

Lägga till en .natvis-fil i ett C++-projekt

Du kan lägga till en .natvis- fil i valfritt C++-projekt.

Så här lägger du till en ny .natvis-fil:

  1. Välj projektnoden C++ i Solution Exploreroch välj Project>Lägg till nytt objekteller högerklicka på projektet och välj Lägg till>Nytt objekt.

    Om du inte ser alla objektmallar väljer du Visa alla mallar.

  2. I dialogrutan Lägg till nytt objekt väljer du Visual C++>Utility>Debugger-visualiseringsfil (.natvis).

  3. Namnge filen och välj Lägg till.

    Den nya filen läggs till i Solution Exploreroch öppnas i dokumentfönstret i Visual Studio.

Visual Studio-felsökningsprogrammet läser in .natvis- filer i C++-projekt automatiskt och innehåller som standard även dem i .pdb--fil när projektet byggs. Om du felsöker den skapade appen läser felsökningsprogrammet in filen .natvis från filen .pdb, även om du inte har projektet öppet. Om du inte vill att filen .natvis ska ingå i .pdbkan du exkludera den från den byggda .pdb--filen.

Om du vill undanta en .natvis--fil från en .pdb-:

  1. Välj filen .natvis i Solution Exploreroch välj ikonen Egenskaper eller högerklicka på filen och välj Egenskaper.

  2. Listrutan visar pilen bredvid Exkluderad från build- och väljer Jaoch väljer sedan OK.

Not

För felsökning av körbara projekt använder du lösningsobjekten för att lägga till alla .natvis- filer som inte finns i .pdbeftersom det inte finns något C++-projekt tillgängligt.

Not

Natvis-regler som läses in från en .pdb- endast gäller för de typer i modulerna som .pdb- refererar till. Om till exempel Module1.pdb har en Natvis-post för en typ med namnet Testgäller den bara för klassen Test i Module1.dll. Om en annan modul också definierar en klass med namnet Testgäller inte posten Module1.pdb Natvis.

Installera och registrera en .natvis--fil via ett VSIX-paket:

Ett VSIX-paket kan installera och registrera .natvis- filer. Oavsett var de installeras hämtas alla registrerade .natvis filer automatiskt under felsökningen.

  1. Inkludera filen .natvis i VSIX-paketet. Till exempel för följande projektfil:

    <?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. Registrera filen .natvis i filen 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-filplatser

Du kan lägga till .natvis- filer i användarkatalogen eller i en systemkatalog om du vill att de ska gälla för flera projekt.

De .natvis--filerna utvärderas i följande ordning:

  1. Samtliga .natvis-filer som är inbäddade i en .pdb som du felsöker, om inte en fil med samma namn finns i det inlästa projektet.

  2. Alla .natvis-filer som finns i ett inläst C++-projekt eller en övergripande lösning. Den här gruppen innehåller alla inlästa C++-projekt, inklusive klassbibliotek, men inte projekt på andra språk.

  3. Alla .natvis filer som installerats och registrerats via ett VSIX-paket.

  1. Den användarspecifika Natvis-katalogen (till exempel %USERPROFILE%\Documents\Visual Studio 2022\Visualizers).
  1. Den användarspecifika Natvis-katalogen (till exempel %USERPROFILE%\Documents\Visual Studio 2019\Visualizers).
  1. Den systemomfattande Natvis-katalogen (<Microsoft Visual Studio-installationsmappen>\Common7\Packages\Debugger\Visualizers). Den här katalogen har .natvis- filer som är installerade med Visual Studio. Om du har administratörsbehörighet kan du lägga till filer i den här katalogen.

Ändra .natvis-filer vid felsökning

Du kan ändra en .natvis--fil i IDE:n när du felsöker projektet. Öppna filen i samma instans av Visual Studio som du felsöker med, ändra den och spara den. Så snart filen har sparats, uppdateras Watch- och Locals-fönstren för att återspegla ändringen.

Du kan också lägga till eller ta bort .natvis- filer i en lösning som du felsöker, och Visual Studio lägger till eller tar bort relevanta visualiseringar.

Du kan inte uppdatera .natvis- filer som är inbäddade i .pdb- filer när du felsöker.

Om du ändrar .natvis- fil utanför Visual Studio börjar ändringarna inte gälla automatiskt. Om du vill uppdatera felsökningsfönstret kan du omvärdera kommandot .natvisreload i fönstret Immediate. Sedan börjar ändringarna gälla utan att felsökningssessionen startas om.

Använd även kommandot .natvisreload för att uppgradera filen .natvis till en nyare version. Till exempel kan .natvis--filen checkas in i källkontrollen och du vill hämta de senaste ändringarna som någon annan har gjort.

Uttryck och formatering

Natvis-visualiseringar använder C++-uttryck för att ange vilka dataobjekt som ska visas. Förutom förbättringarna och begränsningarna för C++-uttryck i felsökningsprogrammet, som beskrivs i Kontextoperator (C++), bör du vara medveten om följande:

  • Natvis-uttryck utvärderas i kontexten för objektet som visualiseras, inte den aktuella stackramen. Till exempel refererar x i ett Natvis-uttryck till fältet med namnet x i objektet som visualiseras, inte till en lokal variabel med namnet x i den aktuella funktionen. Du kan inte komma åt lokala variabler i Natvis-uttryck, även om du kan komma åt globala variabler.

  • Natvis-uttryck tillåter inte funktionsutvärdering eller biverkningar. Funktionsanrop och tilldelningsoperatorer ignoreras. Eftersom felsökarens inbyggda funktioner är sidoeffektfria kan de anropas fritt från alla Natvis-uttryck, även om andra funktionsanrop inte tillåts.

  • Om du vill styra hur ett uttryck visas kan du använda något av de formatspecificerare som beskrivs i Format-specificerare i C++. Formatspecificerare ignoreras när posten används internt av Natvis, till exempel Size-uttrycket i en ArrayItems-expansion.

Not

Eftersom Natvis-dokumentet är XML kan dina uttryck inte direkt använda och-tecknet, större än-tecknet, mindre än-tecknet eller skiftoperatorerna. Du måste undvika dessa tecken i både objekttexten och villkorssatserna. Till exempel:
\<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-vyer

Du kan definiera olika Natvis-vyer för att visa typer på olika sätt. Här är till exempel en visualisering av std::vector som definierar en förenklad vy med namnet simple. Elementen DisplayString och ArrayItems visas i standardvyn och vyn simple, medan objekten [size] och [capacity] inte visas i simple-vyn.

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

I fönstret Watch använder du ,view format-specificeraren för att ange en alternativ vy. Den enkla vyn visas som vec, view(simple):

Klockfönster med enkel vy

Natvis-fel

När felsökaren stöter på fel i en visualiseringspost ignoreras de. Den visar antingen typen i dess råa form eller väljer en annan lämplig visualisering. Du kan använda Natvis-diagnostik för att förstå varför felsökningsprogrammet ignorerade en visualiseringspost och för att se underliggande syntax- och parsningsfel.

Aktivera Natvis-diagnostik:

  • Under Tools>Options (eller Debug>Options) >Debugging>Output Windowska du ställa in Natvis-diagnostikmeddelanden (endast C++) till Fel, Varningeller Utförlig, och välj sedan OK.

Felen visas i fönstret Utdata.

Natvis-syntax referens

Följande element och attribut kan användas i Natvis-filen.

AutoVisualizer-element

Elementet AutoVisualizer är rotnoden i filen .natvis och innehåller attributet för namnområdet xmlns:.

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

Elementet AutoVisualizer kan ha type, HResult, UIVisualizeroch CustomVisualizer underordnade.

Typelement

Ett grundläggande Type ser ut som i det här exemplet:

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

Elementet Type anger:

  1. Vilken typ visualiseringen ska användas för (attributet Name).

  2. Hur värdet för ett objekt av den typen ska se ut (elementet DisplayString).

  3. Hur medlemmarna i typen ska se ut när användaren expanderar typen i ett variabelfönster (den Expand noden).

Mallade klasser

Attributet Name för elementet Type accepterar en asterisk * som jokertecken som kan användas för mallade klassnamn.

I följande exempel används samma visualisering oavsett om objektet är en CAtlArray<int> eller en CAtlArray<float>. Om det finns en specifik visualiseringspost för en CAtlArray<float>har den företräde framför den generiska posten.

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

Du kan referera till mallparametrar i visualiseringsposten med hjälp av makron $T 1, $T 2 och så vidare. Exempel på dessa makron finns i .natvis filer som levereras med Visual Studio.

Matchning av visualiserartyp

Om det inte går att verifiera en visualiseringspost används nästa tillgängliga visualisering.

Ärvbart attribut

Det valfria attributet Inheritable anger om en visualisering endast gäller för en bastyp eller för en bastyp och alla härledda typer. Standardvärdet för Inheritable är true.

I följande exempel gäller visualiseringen endast för den BaseClass typen:

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

Prioritetsattribut

Det valfria attributet Priority anger i vilken ordning alternativa definitioner ska användas om en definition inte kan parsas. Möjliga värden för Priority är: Low, MediumLow,Medium, MediumHighoch High. Standardvärdet är Medium. Attributet Priority skiljer bara mellan prioriteringar inom samma .natvis- fil.

I följande exempel tolkas först posten som matchar 2015 STL. Om det inte går att parsa använder den den alternativa posten för 2013-versionen av STL:

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

Valfritt attribut

Du kan placera ett Optional-attribut på valfri nod. Om en underuttryck inuti en valfri nod inte parsas ignorerar felsökningsprogrammet den noden, men tillämpar resten av Type regler. I följande typ är [State] inte valfritt, men [Exception] är valfritt. Om MyNamespace::MyClass har ett fält med namnet _M_exceptionHoldervisas både noden [State] och den [Exception] noden, men om det inte finns något _M_exceptionHolder fält visas bara den [State] noden.

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

Villkorsattribut

Det valfria Condition-attributet är tillgängligt för många visualiseringselement och anger när en visualiseringsregel ska användas. Om uttrycket i villkorsattributet matchas till falsegäller inte visualiseringsregeln. Om den utvärderas till true, eller om det inte finns något Condition attribut, gäller visualiseringen. Du kan använda det här attributet för if-else-logik i visualiseringsposterna.

Följande visualisering har till exempel två DisplayString element för en smart pekartyp. När _Myptr-medlemmen är tom, resulterar villkoret för det första DisplayString-elementet i true, vilket gör att formuläret visas. När den _Myptr medlemmen inte är tom utvärderas villkoret till falseoch det andra DisplayString-elementet visas.

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

Attributen "IncludeView" och "ExcludeView"

Attributen IncludeView och ExcludeView anger element som ska visas eller inte visas i specifika vyer. I följande Natvis-specifikation för std::vectorvisar simple-vyn till exempel inte [size]- och [capacity] objekten.

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

Du kan använda attributen IncludeView och ExcludeView för typer och enskilda medlemmar.

Versionselement

Elementet Version avgränsar en visualiseringspost till en specifik modul och version. Elementet Version hjälper till att undvika namnkollisioner, minskar oavsiktliga matchningar och tillåter olika visualiseringar för olika typer av versioner.

Om en vanlig rubrikfil som används av olika moduler definierar en typ visas den version av visualiseringen endast när typen finns i den angivna modulversionen.

I följande exempel gäller visualiseringen endast för den DirectUI::Border typ som finns i Windows.UI.Xaml.dll från version 1.0 till 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>

Du behöver inte både Min och Max. De är valfria attribut. Inga jokertecken stöds.

Attributet Name är i formatet filename.ext, till exempel hello.exe eller some.dll. Inga sökvägsnamn tillåts.

DisplayString-elementet

Elementet DisplayString anger en sträng som ska visas som värdet för en variabel. Den accepterar godtyckliga strängar blandat med uttryck. Allt inom klammerparenteser tolkas som ett uttryck. Till exempel följande DisplayString-inlägg:

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

Innebär att variabler av typen CPoint visas som i den här bilden:

Använd ett DisplayString-element

I DisplayString-uttrycket finns x och y, som är medlemmar i CPoint, inom klammerparenteser, så deras värden utvärderas. Exemplet visar också hur du kan undvika klammerparenteser med hjälp av dubbla klammerparenteser ( {{ eller }} ).

Not

Elementet DisplayString är det enda element som accepterar godtyckliga strängar och klammerparentessyntax. Alla andra visualiseringselement accepterar endast uttryck som felsökningsprogrammet kan utvärdera.

StringView-element

Elementet StringView definierar ett värde som felsökaren kan skicka till den inbyggda textvisualiseraren. Till exempel med följande visualisering för ATL::CStringT typ:

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

Det CStringT objektet visas i ett variabelfönster som det här exemplet:

CStringT DisplayString-element

Om du lägger till ett StringView-element talar det om för felsökaren att det kan visa värdet som en textvisualisering.

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

Under felsökningen kan du välja förstoringsglasikonen bredvid variabeln och sedan välja Textvisualiserare för att visa strängen som m_pszData pekar på.

CStringT-data med StringView-visualiserare

Uttrycket {m_pszData,su} innehåller en C++-formatspecificerare suför att visa värdet som en Unicode-sträng. Mer information finns i Format-specificerare i C++.

Expandera element

Den valfria Expand noden anpassar underordnade objekt av en visualiserad typ när du expanderar typen i ett variabelfönster. Noden Expand accepterar en lista över underordnade noder som definierar de underordnade elementen.

  • Om en Expand-nod inte anges i en visualiseringspostering använder barnnoderna standardutökningsreglerna.

  • Om en Expand nod anges utan underordnade noder under den kan typen inte expanderas i felsökningsfönstren.

Objektexpansion

Elementet Item är det mest grundläggande och vanliga elementet i en Expand nod. Item definierar ett enda underordnat element. Till exempel har en CRect-klass med fälten top, left, rightoch bottom följande visualiseringspost:

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

I felsökningsfönstret ser den CRect typen ut som i det här exemplet:

CRect med objektelementexpansion

Felsökningsprogrammet utvärderar de uttryck som anges i elementen Width och Height och visar värdena i kolumnen Value i variabelfönstret.

Felsökningsprogrammet skapar automatiskt [Raw View] nod för varje anpassad expansion. Föregående skärmbild visar [Raw View] nod expanderad för att visa hur standardvyn för objektet skiljer sig från dess Natvis-visualisering. Standardexpansionen skapar ett underträd för basklassen och listar alla datamedlemmar i basklassen som barnnoder.

Not

Om uttrycket för elementet pekar på en komplex typ kan själva -objektet-noden expanderas.

Arrayobjektens expansion

Använd noden ArrayItems för att låta Visual Studio-felsökaren tolka typen som en matris och visa dess enskilda element. Visualiseringen för std::vector är ett bra exempel:

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

En std::vector visar dess enskilda element när de expanderas i variabelfönstret:

std::vector med hjälp av ArrayItems-expansion

Den ArrayItems noden måste ha:

  • Ett Size uttryck (som måste utvärderas till ett heltal) för felsökningsprogrammet för att förstå matrisens längd.
  • Ett ValuePointer uttryck som pekar på det första elementet (som måste vara en pekare av en elementtyp som inte är void*).

Standardvärdet för matrisens nedre gräns är 0. Om du vill åsidosätta värdet använder du ett LowerBound element. De .natvis filer som levereras med Visual Studio har exempel.

Not

Du kan använda []-operatorn, till exempel vector[i], med en endimensionell matrisvisualisering som använder ArrayItems, även om själva typen (till exempel CATLArray) inte tillåter den här operatorn.

Du kan också ange flerdimensionella matriser. I så fall behöver felsökningsprogrammet lite mer information för att korrekt visa underelement:

<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 anger om matrisen är i rad-större eller kolumn-större ordning.
  • Rank anger matrisens rangordning.
  • Elementet Size accepterar den implicita $i-parametern, som den ersätter med dimensionsindexet för att hitta längden på matrisen i den dimensionen.
    • I föregående exempel ska uttrycket _M_extent.M_base[0] ge längden på den 0:e dimensionen, _M_extent._M_base[1] den första och så vidare.
  • LowerBound anger den nedre gränsen för varje dimension i matrisen. För flerdimensionella matriser kan du ange ett uttryck som använder den implicita $i parametern. Parametern $i ersätts med dimensionsindexet för att hitta matrisens nedre gräns i den dimensionen.
    • I föregående exempel börjar alla dimensioner vid 0. Men om du hade ($i == 1) ? 1000 : 100 som den nedre gränsen börjar den 0:e dimensionen vid 100 och den första dimensionen börjar på 1 000.
      • , till exempel [100, 1000], [100, 1001], [100, 1002], ... [101, 1000], [101, 1001],...

Så här ser ett tvådimensionellt Concurrency::array objekt ut i felsökningsfönstret:

tvådimensionell matris med ArrayItems-expansion

IndexListItems utvidgning

Du kan bara använda ArrayItems expansion om matriselementen läggs ut sammanhängande i minnet. Felsökningsprogrammet förflyttar sig till nästa element genom att enkelt öka dess pekare. Om du behöver ändra indexet till värdenoden använder du IndexListItems noder. Här är en visualisering med en IndexListItems nod:

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

Den enda skillnaden mellan ArrayItems och IndexListItems är ValueNode, som förväntar sig det fullständiga uttrycket för det:e-elementet med den implicita parametern $i.

Not

Du kan använda []-operatorn, till exempel vector[i], med en endimensionell matrisvisualisering som använder IndexListItems, även om själva typen (till exempel CATLArray) inte tillåter den här operatorn.

ListaMedLänkadeElement-expansion

Om den visualiserade typen representerar en länkad lista kan felsökaren visa dess barnnoder med en LinkedListItems-nod. Följande visualisering för den CAtlList typen använder 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>

Elementet Size refererar till listans längd. HeadPointer pekar på det första elementet refererar NextPointer till nästa element och ValueNode refererar till objektets värde.

Felsökningsprogrammet utvärderar NextPointer- och ValueNode uttryck i kontexten för LinkedListItems-nodelementet, inte den överordnade listtypen. I föregående exempel har CAtlList en CNode-klass (finns i atlcoll.h) som är en nod i den länkade listan. m_pNext och m_element är fält i den CNode klassen, inte för klassen CAtlList.

ValueNode kan lämnas tom eller använda this för att referera till själva LinkedListItems-noden.

CustomListItems-utvidgning

Med CustomListItems-expansionen kan du skriva anpassad logik för att korsa en datastruktur, till exempel en hashtable. Använd CustomListItems för att visualisera datastrukturer som kan använda C++-uttryck för allt du behöver utvärdera, men som inte riktigt passar formen för ArrayItems, IndexListItemseller LinkedListItems.

Du kan använda Exec för att köra kod inuti en CustomListItems expansion med hjälp av variablerna och objekten som definierats i expansionen. Du kan använda logiska operatorer, aritmetiska operatorer och tilldelningsoperatorer med Exec. Du kan inte använda Exec för att utvärdera funktioner, förutom felsökningsintrinsiska funktioner som stöds av C++-uttrycksutvärderingen.

Följande visualiserare för CAtlMap är ett utmärkt exempel där CustomListItems är lämpligt.

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

Om den visualiserade typen representerar ett träd kan felsökaren navigera i trädet och visa dess barn med hjälp av en TreeItems-nod. Här är visualiseringen för den std::map typen med hjälp av en TreeItems nod:

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

Syntaxen liknar den LinkedListItems noden. LeftPointer, RightPointeroch ValueNode utvärderas i kontexten för trädnodklassen. ValueNode kan lämnas tom eller använda this för att referera till själva TreeItems noden.

UtökatObjekt-utökning

Elementet ExpandedItem genererar en aggregerad barnvy genom att visa egenskaper hos basklasser eller datamedlemmar som om de vore barn till den visualiserade typen. Felsökningsprogrammet utvärderar det angivna uttrycket och lägger till de underordnade noderna i resultatet i den underordnade listan av den visualiserade typen.

Till exempel visas den smarta pekartypen auto_ptr<vector<int>> vanligtvis som:

auto_ptr<vektor<int>> standardexpansion

Om du vill se vektorns värden måste du navigera ner två nivåer i variabelfönstret och gå igenom _Myptr-medlemmen. Genom att lägga till ett ExpandedItem element kan du eliminera _Myptr-variabeln från hierarkin och direkt visa vektorelementen:

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

auto_ptr<vektor<int>> ExpandItem-expansion

I följande exempel visas hur du aggregerar egenskaper från basklassen i en härledd klass. Anta att klassen CPanel härleds från CFrameworkElement. I stället för att upprepa egenskaperna som kommer från basklassen CFrameworkElement lägger visualiseringen ExpandedItem nod till dessa egenskaper i den underordnade listan över klassen CPanel.

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

Den formatspecificeraren, som inaktiverar visualiseringsmatchning för den härledda klassen, är nödvändig här. Annars skulle uttrycket *(CFrameworkElement*)this orsaka att CPanel visualisering tillämpas igen, eftersom matchningsreglerna för standardvisualiseringstypen anser att den är lämpligast. Använd formatspecificerare för att instruera felsökaren att använda basklassvisualiseringen eller standardexpansionen om basklassen inte har någon visualisering.

Expansion av syntetiska objekt

Även om ExpandedItem-elementet ger en plattare vy över data genom att eliminera hierarkier, gör Synthetic-noden motsatsen. Det gör att du kan skapa ett artificiellt underordnat element som inte är ett resultat av ett uttryck. Det artificiella elementet kan ha barnelement av sitt eget. I följande exempel använder visualiseringen för den Concurrency::array typen en Synthetic nod för att visa ett diagnostikmeddelande för användaren:

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

Samtidighet::Matris med syntetisk elementexpansion

Inbyggd expansion

En anpassad inbyggd funktion som kan anropas från ett uttryck. Ett <Intrinsic>-element måste åtföljas av en felsökningskomponent som implementerar funktionen via gränssnittet IDkmIntrinsicFunctionEvaluator140. Mer information om hur du implementerar en anpassad inbyggd funktion finns i Implementera anpassad NatVis-funktion.

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

Med elementet HResult kan du anpassa informationen som visas för en HRESULT- i felsökningsfönster. Elementet HRValue måste innehålla 32-bitarsvärdet för HRESULT- som ska anpassas. Elementet HRDescription innehåller den information som ska visas i felsökningsfönstret.


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

UIVisualizer-element

Ett UIVisualizer-element registrerar ett plugin-program för grafisk visualisering med felsökningsprogrammet. En grafisk visualiserare skapar en dialogruta eller ett annat gränssnitt som visar en variabel eller ett objekt på ett sätt som överensstämmer med dess datatyp. Visualiserarens plugin måste skrivas som en VSPackage-och måste tillhandahålla en tjänst som debuggern kan använda. Filen .natvis innehåller registreringsinformation för plugin-programmet, till exempel dess namn, den globalt unika identifieraren (GUID) för den exponerade tjänsten och de typer som den kan visualisera.

Här är ett exempel på ett UIVisualizer-element:

<?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>
  • Ett ServiceId - Id attributpar identifierar en UIVisualizer. ServiceId är GUID för tjänsten som visualiserarpaketet exponerar. Id är en unik identifierare som skiljer visualiserare åt, om en tjänst tillhandahåller mer än en. I föregående exempel tillhandahåller samma visualiseringstjänst två visualiserare.

  • Attributet MenuName definierar ett visualiserarnamn som ska visas i listrutan bredvid förstoringsglasikonen i felsökningsprogrammet. Till exempel:

    snabbmeny för UIVisualizer-menyn

Varje typ som definieras i filen .natvis måste uttryckligen visa alla visualiserare för användargränssnittet som kan visa den. Felsökningsprogrammet matchar visualiserarreferenserna i typposterna med registrerade visualiserare. Följande typpost för std::vector refererar till UIVisualizer i föregående exempel.

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

Du kan se ett exempel på en UIVisualizer i Image Watch-tillägget som används för att visa minnesinterna bitmappar.

CustomVisualizer-element

CustomVisualizer är en utökningspunkt som anger ett VSIX-tillägg som du skriver för att styra visualiseringar i Visual Studio Code. Mer information om hur du skriver VSIX-tillägg finns i Visual Studio SDK.

Det är mycket mer arbete att skriva en anpassad visualiserare än en XML Natvis-definition, men du är fri från begränsningar om vad Natvis gör eller inte stöder. Anpassade visualiserare har åtkomst till den fullständiga uppsättningen utöknings-API:er för felsökningsprogram, som kan köra frågor mot och ändra felsökningsprocessen eller kommunicera med andra delar av Visual Studio.

Du kan använda attributen Condition, IncludeViewoch ExcludeViewCustomVisualizer element.

Begränsningar

Natvis-anpassningar fungerar med klasser och strukturer, men inte med typdefinieringar.

Natvis stöder inte visualiseringar för primitiva typer (till exempel int, bool) eller för pekare till primitiva typer. I det här scenariot är ett alternativ att använda formatspecificeraren lämplig för ditt användningsfall. Om du till exempel använder double* mydoublearray i koden kan du använda en matrisformatsspecificerare i felsökningsprogrammets fönster Watch, till exempel uttrycket mydoublearray, [100], som visar de första 100 elementen.