Condividi tramite


Visualizzazione del debug nativo di Visual Studio (natvis) per C++/WinRT

L’estensione di Visual Studio C++/WinRT (VSIX) offre la visualizzazione del debug nativo di Visual Studio (natvis) dei tipi proiettati C++/WinRT. In questo modo si ottiene un'esperienza simile al debug di C#.

Nota

Per altre informazioni sull'estensione di Visual Studio C++/WinRT (VSIX), vedere supporto di Visual Studio per C++/WinRT e VSIX.

Abilitazione di natvis

Natvis viene attivato automaticamente per una compilazione di debug perché WINRT_NATVIS viene definito quando viene definito il simbolo _DEBUG.

Ecco come acconsentire esplicitamente a una build di versione.

  • Compilare il codice con il simbolo WINRT_NATVIS definito. In questo modo viene esportata una funzione WINRT_abi_val, che fornisce il punto di ingresso per il visualizzatore di debug per valutare i valori delle proprietà nel processo di destinazione.
  • Generare un PDB completo. Questo perché il visualizzatore di debug usa l'analizzatore di espressioni C++ di Visual Studio, che a sua volta richiede definizioni simboliche per i tipi di proprietà visualizzati.
  • Un tipo visualizzato deve segnalare una classe di runtime o un'interfaccia definita nei metadati individuabili. Questa operazione viene eseguita tramite l'implementazione di IInspectable::GetRuntimeClassName.

Dato quanto sopra, il visualizzatore di debug funziona meglio con i tipi di sistema Windows per i quali i metadati sono disponibili nella cartella C:\Windows\System32\WinMetadata. Tuttavia, può supportare anche i tipi definiti dall'utente e il debug remoto, purché sia possibile individuare correttamente i file .winmd.

Utilizzo di metadati personalizzati

Il visualizzatore di debug cerca i metadati definiti dall'utente (file.winmd ) insieme al processo .exe. Usa un algoritmo simile a quello di RoGetMetaDataFile, che esegue il probe per sottostringhe successive del nometipo completo. Ad esempio, se il tipo visualizzato è Contoso.Controls.Widget, il visualizzatore cerca, in sequenza, per:

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

Debug remoto con metadati personalizzati

Quando si esegue il debug remoto, il processo .exe non è locale, quindi la ricerca di metadati personalizzati (menzionata nella sezione precedente) ha esito negativo. In tal caso, il visualizzatore esegue il fallback a una cartella della cache locale (%TEMP%) per un file di .winmd appropriato. Se ne trova uno, registra le dimensioni e la data del file e quindi cerca nella destinazione di debug remoto lo stesso .winmd insieme al file binario. Se necessario, il file remoto viene scaricato, aggiornando la cache locale. Questa strategia garantisce che il .winmd memorizzato nella cache locale sia sempre aggiornato, oltre a fornire un mezzo per memorizzare manualmente nella cache un oggetto .winmd se non è possibile trovarlo in remoto (ad esempio, se la distribuzione F5 non l'ha inserita).

Per un esempio del comportamento di memorizzazione nella cache, vedere la sezione risoluzione dei problemi di seguito.

Risoluzione dei problemi

Il visualizzatore di debug usa l'analizzatore di espressioni C++ di Visual Studio per richiamare la funzione WINRT_abi_val esportata per ottenere i valori delle proprietà. In genere, il visualizzatore può intercettare eccezioni non gestite e ridurre normalmente la visualizzazione di "<Oggetto non inizializzato o informazioni non disponibili>" in Visual Studio Espressioni di controllo finestre.

Ciò è utile quando il visualizzatore tenta di valutare una variabile locale al di fuori dell'ambito di durata, ad esempio prima della costruzione. In alcuni contesti, ad esempio unit test, viene installato un filtro eccezioni non gestito. Ciò può causare l'interruzione del processo quando si verifica un errore dell'analizzatore di espressioni C++. Per evitare errori, il visualizzatore effettua diverse chiamate VirtualQuery in WINRT_abi_val.

Diagnostica

Se una proprietà non viene visualizzata correttamente, attivare la diagnostica natvis dettagliata in Visual Studio (Strumenti di>opzioni>debug>finestra di output>messaggi di diagnostica Natvis), osservare quindi la finestraOutput per gli errori natvis.

L'estratto seguente mostra diversi tentativi di probe per un file .winmd, seguito da un download dalla destinazione remota alla cartella della cache locale e quindi da un carico di tale file .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

Se il visualizzatore non riesce a trovare un file .winmd, viene generato questo errore:

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

Esistono diversi altri scenari di errore che producono tutti la diagnostica.

Se i metadati sono disponibili, la diagnostica di output mostrerà molte chiamate simili alla seguente:

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

La prima è una chiamata a IStringable.ToString per ottenere la rappresentazione di stringa di un tipo complesso (valore di visualizzazione non espanso).

Il secondo è una chiamata a IInspectable::GetRuntimeClassName, per riflettere sulle proprietà del tipo.

Le chiamate successive WINRT_abi_val sono valutazioni delle proprietà per ogni interfaccia individuata nel tipo.

Richiamo di WINRT_abi_val

È possibile utilizzare le finestre di Immediate/Command per invocare direttamente WINRT_abi_val per la risoluzione dei problemi.

Ad esempio, data una variabile proiettata stringable, è possibile valutarne IStringable.ToString come:

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