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.
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.
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:
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.
I dialogrutan Lägg till nytt objekt väljer du Visual C++>Utility>Debugger-visualiseringsfil (.natvis).
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-:
Välj filen .natvis i Solution Exploreroch välj ikonen Egenskaper eller högerklicka på filen och välj Egenskaper.
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 Test
gäller den bara för klassen Test
i Module1.dll. Om en annan modul också definierar en klass med namnet Test
gä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.
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>
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:
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.
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.
Alla .natvis filer som installerats och registrerats via ett VSIX-paket.
- Den användarspecifika Natvis-katalogen (till exempel %USERPROFILE%\Documents\Visual Studio 2022\Visualizers).
- Den användarspecifika Natvis-katalogen (till exempel %USERPROFILE%\Documents\Visual Studio 2019\Visualizers).
- 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 \>\> 24),x\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \& 0xFF000000) == 0"\>"None"\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \& 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<*>">
<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):
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:
Vilken typ visualiseringen ska användas för (attributet
Name
).Hur värdet för ett objekt av den typen ska se ut (elementet
DisplayString
).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<*>">
<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
, MediumHigh
och 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<*>" Priority="MediumLow">
<DisplayString>{_Callee}</DisplayString>
<Expand>
<ExpandedItem>_Callee</ExpandedItem>
</Expand>
</Type>
<!-- VC 2015 -->
<Type Name="std::reference_wrapper<*>">
<DisplayString>{*_Ptr}</DisplayString>
<Expand>
<Item Name="[ptr]">_Ptr</Item>
</Expand>
</Type>
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_exceptionHolder
visas 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 false
gä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 false
och det andra DisplayString
-elementet visas.
<Type Name="std::auto_ptr<*>">
<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::vector
visar simple
-vyn till exempel inte [size]
- och [capacity]
objekten.
<Type Name="std::vector<*>">
<DisplayString>{{ size={_Mylast - _Myfirst} }}</DisplayString>
<Expand>
<Item Name="[size]" ExcludeView="simple">_Mylast - _Myfirst</Item>
<Item Name="[capacity]" ExcludeView="simple">_Myend - _Myfirst</Item>
<ArrayItems>
<Size>_Mylast - _Myfirst</Size>
<ValuePointer>_Myfirst</ValuePointer>
</ArrayItems>
</Expand>
</Type>
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:
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<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
</Type>
Det CStringT
objektet visas i ett variabelfönster som det här exemplet:
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<wchar_t,*>">
<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å.
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
, right
och 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:
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<*>">
<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:
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 ärvoid*
).
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<*,*>">
<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.
- I föregående exempel ska uttrycket
-
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],...
- , till exempel
- I föregående exempel börjar alla dimensioner vid 0. Men om du hade
Så här ser ett tvådimensionellt Concurrency::array
objekt ut i felsökningsfönstret:
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<*>">
<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<*,*>">
<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
, IndexListItems
eller 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<*,*,*,*>">
<AlternativeType Name="ATL::CMapToInterface<*,*,*>"/>
<AlternativeType Name="ATL::CMapToAutoPtr<*,*,*>"/>
<DisplayString>{{Count = {m_nElements}}}</DisplayString>
<Expand>
<CustomListItems MaxItemsPerView="5000" ExcludeView="Test">
<Variable Name="iBucket" InitialValue="-1" />
<Variable Name="pBucket" InitialValue="m_ppBins == nullptr ? nullptr : *m_ppBins" />
<Variable Name="iBucketIncrement" InitialValue="-1" />
<Size>m_nElements</Size>
<Exec>pBucket = nullptr</Exec>
<Loop>
<If Condition="pBucket == nullptr">
<Exec>iBucket++</Exec>
<Exec>iBucketIncrement = __findnonnull(m_ppBins + iBucket, m_nBins - iBucket)</Exec>
<Break Condition="iBucketIncrement == -1" />
<Exec>iBucket += iBucketIncrement</Exec>
<Exec>pBucket = m_ppBins[iBucket]</Exec>
</If>
<Item>pBucket,na</Item>
<Exec>pBucket = pBucket->m_pNext</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
TreeItems-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<*>">
<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
, RightPointer
och 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:
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<*>">
<DisplayString>auto_ptr {*_Myptr}</DisplayString>
<Expand>
<ExpandedItem>_Myptr</ExpandedItem>
</Expand>
</Type>
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<*,*>">
<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>
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<*>">
<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 enUIVisualizer
.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:
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<int,*>">
<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
, IncludeView
och ExcludeView
på CustomVisualizer
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.