C++/WinRT 用 Visual Studio ネイティブ デバッグ視覚化 (natvis)

C++/WinRT Visual Studio 拡張機能 (VSIX) は、C++/WinRT の投影された型の Visual Studio ネイティブのデバッグの視覚化 (natvis) を提供します。 これにより、C# デバッグと同様のエクスペリエンスが実現します。

注意

C++/WinRT Visual Studio Extension (VSIX) についての詳細は、「C++/WinRT の Visual Studio サポートと VSIX」を参照してください。

Natvis の有効化

_DEBUG シンボルが定義されているときには WINRT_NATVIS が定義されているため、デバッグ ビルドの場合、Natvis は自動的にオンになります。

次にリリース ビルドに対してこれを選択する方法を示します。

  • シンボル WINRT_NATVIS 定義されたコードをコンパイルします。 これにより、WINRT_abi_val 関数がエクスポートされることで、デバッグ ビジュアライザーがターゲットプロセスのプロパティ値を評価するためのエントリ ポイントが提供されます。
  • 完全な PDB を生成します。 これは、デバッグ ビジュアライザーが Visual Studio C++ の式エバリュエーターを使用し、そのために、表示されるプロパティの型にシンボリック定義が必要になるためです。
  • 視覚化された型は、検出可能なメタデータで定義されているランタイム クラスまたはインターフェイスを報告する必要があります。 これは、IInspectable::GetRuntimeClassName の実装によって行われます。

上記の場合、デバッグ ビジュアライザーは、C:\Windows\System32\WinMetadata フォルダーでメタデータを見つけることができるような Windows システムで最適に機能します。 ただし、.winmd ファイルを適切に見つけることができる場合は、ユーザー定義型とリモート デバッグもサポートできます。

カスタム メタデータの使用

デバッグ ビジュアライザーでは、プロセスの .exe と共にユーザー定義のメタデータ (.winmd ファイル) が検索さ ます。 RoGetMetaDataFile のようなアルゴリズムを使用して、完全修飾された型名の連続する部分文字列を調査します。 たとえば、視覚化される型が Contoso.Controls.Widget の場合、ビジュアライザーは次のものを順番に探します。

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

カスタム メタデータを使用したリモート デバッグ

リモートデバッグの場合、プロセスの .exe はローカルではないため、(前のセクションで説明した) カスタム メタデータの検索は失敗します。 この場合、ビジュアライザーは、適切な .winmd ファイルのローカル キャッシュ フォルダー (%TEMP%) にフォール バックし ます。 見つかった場合は、ファイルのサイズと日付を記録し、次に、同じ .winmd のリモート デバッグ ターゲットをバイナリと共に検索します。 必要に応じて、リモート ファイルがダウンロードされ、ローカル キャッシュが更新されます。 この戦略により、ローカルにキャッシュされた .winmd が常に最新の状態になり、手動でキャッシュする手段も提供されます。リモートで見つからない場合 (たとえば、F5 による展開でそこに配置されなかった場合) に winmd を手動でキャッシュする手段が提供されます。

キャッシュ動作の例については、後述の「トラブルシューティング」セクションを参照してください。

トラブルシューティング

デバッグ ビジュアライザーは、Visual Studio C++ 式エバリュエーターを使用して、エクスポートされた WINRT_abi_val 関数を呼び出してプロパティ値を取得します。 通常、ビジュアライザーは未処理の例外をキャッチして適切にレベルを低下させ、Visual Studio の [ウォッチ] ウィンドウに "<Object uninitialized or information unavailable>" (オブジェクトが初期化されていないか、情報が利用できません) を表示します。

これは、ビジュアライザーが有効期間の範囲外 (構築前など) にローカル変数を評価しようとしたときに便利です。 単体テストなどの一部のコンテキストでは、ハンドルされない例外フィルターがインストールされます。 これにより、C++ 式エバリュエーターで障害が発生したときにプロセスが終了することがあります。 障害を回避するために、ビジュアライザーは、WINRT_abi_val でいくつかの VirtualQuery の呼び出しを行います。

診断

プロパティが正しく表示されていない場合は、Visual Studio で詳細な Natvis 診断をオンにし ([ツール]>[オプション]>[デバッグ]>[出力ウィンドウ]>[Natvis 診断メッセージ])、[出力] ウィンドウで Natvis エラーを確認します。

次の抜粋では、.winmd ファイルをプローブした後に、リモート ターゲットからローカル キャッシュ フォルダーにダウンロードし、さらにその .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

ビジュアライザーが .winmd ファイルを見つけられなかった場合、次のエラーが生成されます。

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

他にもいくつかのエラー シナリオがあり、そのすべてで診断が生成されます。

メタデータを使用できる場合、出力診断では次のような多くの呼び出しが表示されます。

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

1 つ目は、複合型の文字列形式 (展開されていない表示値) を取得するための IStringable.ToString の呼び出しです。

2 つ目は、型のプロパティに反映させるための IInspectable::GetRuntimeClassNameの呼び出しです。

後続の WINRT_abi_val の呼び出しは、型で検出された各インターフェイスのプロパティの評価です。

WINRT_abi_val の呼び出し

Visual Studio の [イミディエイト]/[コマンド] ウィンドウを使用すると、トラブルシューティングのために WINRT_abi_val を直接呼び出すことができます。

たとえば、想定される変数 stringable が指定されると、その IStringable.ToString を次のように評価できます。

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