Visualisation native du débogage Visual Studio (natvis) pour C++/WinRT

L’extension Visual Studio C++/WinRT (VSIX) vous offre une visualisation native du débogage Visual Studio (natvis) des types projetés C++/WinRT. Vous bénéficiez ainsi d’une expérience similaire à celle du débogage C#.

Notes

Pour plus d’informations, consultez Prise en charge de Visual Studio pour C++/WinRT et VSIX.

Activation de natvis

Natvis est activé automatiquement pour une build de débogage, car WINRT_NATVIS est défini quand le symbole _DEBUG est défini.

Voici comment l’activer pour une build de mise en production.

  • Compilez votre code avec le symbole WINRT_NATVIS défini. Cette opération exporte une fonction WINRT_abi_val, qui fournit le point d’entrée pour le visualiseur de débogage afin d’évaluer les valeurs de propriété dans le processus cible.
  • Générez un fichier PDB complet. Cette opération est nécessaire, car le visualiseur de débogage utilise l’évaluateur d’expression C++ Visual Studio, qui à son tour nécessite des définitions symboliques pour les types de propriété affichés.
  • Un type visualisé doit signaler une classe runtime ou une interface définie dans les métadonnées découvrables. Pour ce faire, il utilise son implémentation de IInspectable::GetRuntimeClassName.

Ainsi, le visualiseur de débogage fonctionne mieux avec les types système Windows pour lesquels des métadonnées sont disponibles dans le dossier C:\Windows\System32\WinMetadata. Toutefois, il peut également prendre en charge les types définis par l’utilisateur et le débogage à distance, à condition que vous localisiez correctement les fichiers .winmd.

Utilisation de métadonnées personnalisées

Le visualiseur de débogage recherche les métadonnées définies par l’utilisateur (fichiers .winmd) en même temps que le processus .exe. Il utilise un algorithme similaire à celui de RoGetMetaDataFile, en recherchant des sous-chaînes successives du nom de type complet. Par exemple, si le type visualisé est Contoso.Controls.Widget, le visualiseur recherche successivement :

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

Débogage à distance avec métadonnées personnalisées

Lors du débogage à distance, le processus .exe n’est pas local, ce qui entraîne l’échec de la recherche de métadonnées personnalisées (mentionnée dans la section précédente). Dans ce cas, le visualiseur se rabat sur un dossier de cache local (%TEMP%) pour obtenir un fichier .winmd approprié. S’il en trouve un, il enregistre la taille et la date du fichier, puis recherche dans la cible de débogage distant le même .winmd avec le binaire. Si nécessaire, le fichier distant est téléchargé, entraînant la mise à jour du cache local. Cette stratégie permet de s’assurer que le .winmd mis en cache localement est toujours à jour et offre un moyen de mettre en cache manuellement un .winmd s’il est introuvable à distance (par exemple, si un déploiement F5 ne l’a pas stocké à distance).

Pour obtenir un exemple du comportement de mise en cache, consultez la section Dépannage ci-dessous.

Dépannage

Le visualiseur de débogage utilise l’évaluateur d’expression C++ Visual Studio pour appeler la fonction WINRT_abi_val exportée afin d’obtenir des valeurs de propriété. Normalement, le visualiseur peut intercepter les exceptions non gérées et effectuer un arrêt normal, en affichant « <Objet non initialisé ou informations non disponibles> » dans les fenêtres Espion de Visual Studio.

C’est utile quand le visualiseur tente d’évaluer une variable locale en dehors de la portée de sa durée de vie (par exemple, avant la construction). Dans certains cas, tels que les tests unitaires, un filtre d’exception non prise en charge est installé. Cela peut entraîner l’arrêt du processus quand l’évaluateur d’expression C++ rencontre des erreurs. Pour éviter les défaillances, le visualiseur effectue plusieurs appels VirtualQuery dans WINRT_abi_val.

Diagnostics

Si une propriété ne s’affiche pas correctement, activez les diagnostics natvis détaillés dans Visual Studio (Outils>Options>Débogage>Fenêtre Sortie>Messages de diagnostic natvis), puis déterminez si la fenêtre Sortie contient des erreurs natvis.

L’extrait suivant montre plusieurs tentatives de recherche d’un fichier .winmd, suivies d’un téléchargement de la cible distante vers le dossier de cache local, puis d’un chargement de ce fichier .winmd.

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

Si le visualiseur ne parvient pas à trouver un fichier .winmd, cette erreur est générée :

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

Il existe un certain nombre d’autres scénarios d’erreur qui produisent tous des diagnostics.

Si des métadonnées sont disponibles, les diagnostics de sortie affichent de nombreux appels comme ceux-ci :

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

Le premier est un appel à IStringable.ToString pour obtenir la représentation sous forme de chaîne d’un type complexe (la valeur d’affichage non développée).

Le deuxième est un appel à IInspectable::GetRuntimeClassName, afin de refléter les propriétés du type.

Les appels de WINRT_abi_val suivants sont des évaluations de propriété pour chaque interface découverte sur le type.

Appel de WINRT_abi_val

Vous pouvez utiliser les fenêtres Visual Studio Exécution/Commande pour appeler directement WINRT_abi_val à des fins de résolution des problèmes.

Par exemple, vous pouvez évaluer le IStringable.ToString d’une variable projetée stringable comme suit :

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