C++/WinRT Visual Studio 延伸模組(VSIX)可為您提供 Visual Studio 原生偵錯視覺化(natvis),以用於 C++/WinRT 投影類型。 這能提供類似 C# 除錯的體驗。
Note
欲了解更多關於 C++/WinRT Visual Studio 擴充套件(VSIX)的資訊,請參見 Visual Studio 對 C++/WinRT 及 VSIX 的支援。
啟用 NATVIS
Natvis 在除錯建置時會自動開啟,因為 WINRT_NATVIS 在定義 _DEBUG 符號時已經定義。
以下說明如何為發布版本啟用此功能。
- 編譯您的程式碼時,請定義符號 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 不是本地的,因此搜尋自訂元資料(如前一節所述)會失敗。 此時,視覺化工具會回退至本地快取資料夾(%TEMP%)以存放合適的 .winmd 檔案。 如果找到,就會記錄該檔案的大小和日期,然後在遠端除錯目標上搜尋與二進位檔並存的相同 .winmd。 必要時會下載遠端檔案,更新本地快取。 此策略可確保本機快取的 .winmd 始終保持最新狀態,並提供可手動快取 的方法。
winmd 如果無法在遠端找到它(例如,如果 F5 部署時沒有把它放在那裡)。
如需快取行為的範例,請參閱下方的 疑難排解 章節。
Troubleshooting
除錯視覺化工具使用 Visual Studio C++ 表達式評估器(Expression Evaluator)來呼叫匯出的 WINRT_abi_val 函式以取得屬性值。 通常,視覺化工具可以偵測未處理的例外,並優雅地降級,在 Visual Studio < 視窗中顯示「>物件未初始化或資訊不可得」。
當視覺化工具嘗試評估超出其壽命範圍的局部變數時(例如建構前),這非常有用。 在某些情境下,例如單元測試,會安裝未處理的例外過濾器。 這可能導致當 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
第一個是呼叫 IStringable.ToString ,以取得複雜型態的字串表示(未展開的顯示值)。
第二個是呼叫 IInspectable::GetRuntimeClassName,以反映該型態的屬性。
後續的 WINRT_abi_val 呼叫是對該型別中發現的每個介面的性質評估。
Invoking 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"