Visual Studio Native Debugvisualisierung (natvis) für C++/WinRT

Mit der C++/WinRT Visual Studio Extension (VSIX) erhalten Sie die Native Debugvisualisierung (natvis) von Visual Studio für C++/WinRT-Projekttypen. Dadurch erreichen Sie ein ähnliches Verhalten wie beim Debuggen von C#.

Hinweis

Weitere Informationen zur C++/WinRT Visual Studio Extension (VSIX) finden Sie unter Visual Studio-Unterstützung für C++/WinRT und VSIX.

Aktivieren von natvis

Natvis ist für einen Debugbuild automatisch eingeschaltet, da WINRT_NATVIS definiert wird, wenn das _DEBUG-Symbol definiert wird.

Hier erfahren Sie, wie Sie es für einen Releasebuild verwenden.

  • Kompilieren Sie Ihren Code, wobei das Symbol WINRT_NATVIS definiert ist. Auf diese Weise wird eine WINRT_abi_val-Funktion exportiert, die den Einstiegspunkt für die Debug-Schnellansicht bereitstellt, um Eigenschaftswerte im Zielprozess auszuwerten.
  • Generieren Sie eine vollständige PDB-Datei. Dies liegt daran, dass die Debug-Schnellansicht die Visual Studio C++-Ausdrucksauswertung verwendet, die wiederum symbolische Definitionen für angezeigte Eigenschaftstypen erfordert.
  • Ein visualisierter Typ muss eine Laufzeitklasse oder eine Schnittstelle melden, die in erkennbaren Metadaten definiert ist. Dies erfolgt über die Implementierung von IInspectable::GetRuntimeClassName.

Im obigen Beispiel funktioniert die Debug-Schnellansicht am besten mit Windows-Systemtypen, für die Metadaten im Ordner C:\Windows\System32\WinMetadata zu finden sind. Sie kann jedoch auch benutzerdefinierte Typen und das Remotedebuggen unterstützen, vorausgesetzt, Sie finden .winmd-Dateien ordnungsgemäß.

Verwenden von benutzerdefinierten Metadaten

Die Debug-Schnellansicht sucht neben dem Prozess .exe nach benutzerdefinierten Metadaten (.winmd-Dateien). Es wird ein Algorithmus verwendet, der dem von RoGetMetaDataFile ähnelt und nach aufeinander folgenden Teilzeichenfolgen des vollqualifizierten Typnamens sucht. Wenn der visualisierte Typ beispielsweise Contoso.Controls.Widget lautet, sucht die Schnellansicht nacheinander nach Folgendem:

  • Contoso.Controls.Widget.winmd
  • Contoso.Controls.winmd
  • Contoso.winmd

Remotedebuggen mit benutzerdefinierten Metadaten

Beim Remotedebuggen ist der Prozess .exe nicht lokal, daher schlägt die Suche nach benutzerdefinierten Metadaten (im vorherigen Abschnitt erwähnt) fehl. In diesem Fall verwendet die Schnellansicht einen lokalen Cacheordner (%TEMP%), um eine geeignete .winmd-Datei zu finden. Wenn eine Datei gefunden wird, werden Größe und Datum der Datei erfasst, und das Remotedebugging-Ziel wird dann neben der Binärdatei nach derselben .winmd-Datei durchsucht. Bei Bedarf wird die Remotedatei heruntergeladen, und der lokale Cache wird aktualisiert. Diese Strategie stellt sicher, dass die lokal zwischengespeicherte .winmd-Datei immer auf dem neuesten Stand ist, und bietet eine Möglichkeit zum manuellen Zwischenspeichern einer .-Datei,winmd, wenn sie nicht remote gefunden werden kann (z. B. wenn die F5-Bereitstellung sie nicht dort angezeigt hat).

Ein Beispiel für das Verhalten beim Zwischenspeichern finden Sie im Abschnitt Problembehandlung weiter unten.

Problembehandlung

Die Debug-Schnellansicht verwendet die Visual Studio C++-Ausdrucksauswertung, um die exportierte WINRT_abi_val-Funktion zum Abrufen von Eigenschaftswerten aufzurufen. Normalerweise kann die Schnellansicht nicht behandelte Ausnahmen abfangen und ordnungsgemäß herabgestuft werden, wobei in den Fenstern Überwachen von Visual Studio „<Objekt nicht initialisiert oder keine Informationen verfügbar>“ angezeigt wird.

Dies ist nützlich, wenn die Schnellansicht versucht, eine lokale Variable außerhalb ihres Lebensdauerbereichs (z. B. vor der Konstruktion) auszuwerten. In einigen Kontexten, z. B. Komponententests, wird ein Filter für nicht behandelte Ausnahmen installiert. Dies kann dazu führen, dass der Prozess beendet wird, wenn die C++-Ausdrucksauswertung einen Fehler verursacht. Um Fehler zu verhindern, führt die Schnellansicht mehrere VirtualQuery-Aufrufe in WINRT_abi_val aus.

Diagnose

Wenn eine Eigenschaft nicht ordnungsgemäß angezeigt wird, aktivieren Sie die ausführliche natvis-Diagnose in Visual Studio (Extras>Optionen>Debugging>Ausgabefenster>Natvis-Diagnosemeldungen), und prüfen Sie dann das Fenster Ausgabe auf natvis-Fehler.

Der folgende Auszug zeigt mehrere Versuche, nach einer .winmd-Datei zu suchen, gefolgt von einem Download vom Remoteziel in den lokalen Cacheordner und dem anschließenden Laden dieser .winmd-Datei.

Natvis C++/WinRT: Looking for C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.Widget.winmd
Natvis C++/WinRT: Looking for C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.winmd
Natvis C++/WinRT: Downloading C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.winmd
Natvis C++/WinRT: Loaded C:\Users\...\AppData\Local\Temp\Consoso.Controls.winmd

Wenn die Schnellansicht keine .winmd-Datei findet, wird der folgende Fehler generiert:

Natvis C++/WinRT: Could not find metadata for Consoso.Controls.Widget

Es gibt eine Reihe anderer Fehlerszenarien, die alle Diagnosen erzeugen.

Wenn Metadaten verfügbar sind, zeigt die Ausgabendiagnose viele Aufrufe wie die folgenden an:

Natvis C++/WinRT: WINRT_abi_val(*(::IUnknown**)0x32dd4ffc18, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
Natvis C++/WinRT: WINRT_abi_val(*(::IUnknown**)0x32dd4ffc18, L"{AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90}", -2).s,sh

Der erste Aufruf ist ein Aufruf von IStringable.ToString, um die Zeichenfolgendarstellung eines komplexen Typs (der nicht erweiterte Anzeigewert) abzurufen.

Der zweite Aufruf ist ein Aufruf von IInspectable::GetRuntimeClassName, um die Eigenschaften des Typs widerzuspiegeln.

Nachfolgende WINRT_abi_val-Aufrufe sind Eigenschaftsauswertungen für jede Schnittstelle, die für den Typ ermittelt wurde.

Aufrufen von WINRT_abi_val

Sie können die Visual Studio-Fenster Immediate/Befehl verwenden, um WINRT_abi_val direkt für die Problembehandlung aufzurufen.

Bei der projizierten Variable stringable beispielsweise können Sie IStringable.ToString folgendermaßen auswerten:

>? WINRT_abi_val((::IUnknown*)&stringable, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
L"string"