C++/WinRT 問題疑難排解

Note

關於安裝及使用 C++/WinRT Visual Studio 擴充功能(VSIX)(提供專案範本支援)的資訊,請參見 Visual Studio 對 C++/WinRT 的支援

這個主題一開始就說明,讓你能立刻知道;即使你現在還不需要。 以下的故障排除症狀與解決方法表格,無論你是在剪新程式碼還是移植現有應用程式,都可能對你有幫助。 如果你正在移植,並且渴望繼續推進,達到專案建置和執行的階段,那麼你可以透過註解或刪除任何非必要的問題程式碼來暫時取得進展,然後再回頭還清這些債務。

有關常見問題清單,請參見「 常見問題」。

追查 XAML 問題

XAML 的解析異常很難診斷——尤其是當例外中沒有有意義的錯誤訊息時。 請確認除錯器已設定為可捕捉首次機會例外(以便儘早嘗試捕捉剖析例外)。 你或許可以檢查除錯器中的例外變數,判斷 HRESULT 或訊息是否有任何有用資訊。 另外,請查看 Visual Studio 的輸出視窗,看看 XAML 解析器會輸出錯誤訊息。

如果你的應用程式終止執行,而你只知道在剖析 XAML 標記時發生了未處理的例外,那可能是因為以索引鍵參考了遺失的資源所導致。 或者,它可能是在 UserControl、自訂控制項或自訂版面面板中拋出的例外。 最後的手段是二元分裂。 從 XAML 頁面移除大約一半的標記,然後重新執行應用程式。 這樣你就能知道錯誤是在你移除的那半部分(無論如何都應該還原)還是你沒移除的那部分。 重複這個過程,將包含錯誤的那一半分成一組,依此類推,直到你鎖定問題所在。

症狀與治療方法

癥狀 補救方法
執行時會拋出一個例外,HRESULT 值為 REGDB_E_CLASSNOTREGISTERED。 請參見「為什麼我會遇到「課程未註冊」例外?
C++ 編譯器會產生錯誤:「'implements_type': 不是任何直接或間接的『<投影型別>』基底類別成員」。 當你以實作型別未限定命名空間的名稱(例如 MyRuntimeClass)呼叫 make,且尚未包含該型別的標頭檔時,就可能會發生這種情況。 編譯器將 MyRuntimeClass 解釋為投影型別。 解決方法是包含你的實作類型的標頭(MyRuntimeClass.h例如 )。
C++ 編譯器會產生「嘗試引用已刪除函式」的錯誤。 這可能發生在你呼叫 make ,而你傳遞給模板參數的實作類型有 = delete 預設建構子時。 編輯實作類型的標頭檔並改 = delete= default。 你也可以在 IDL 裡為執行時類別加入建構子。
你已經實作 了 INotifyPropertyChanged,但你的 XAML 綁定沒有更新(UI 也沒有訂閱 PropertyChanged)。 記得在 XAML 標記中的繫結運算式上設定 Mode=OneWay(或 TwoWay)。 請參見 XAML 控制項;綁定到 C++/WinRT 屬性
你綁定一個 XAML 項目控制到可觀察集合,執行時會拋出一個例外,訊息是「參數錯誤」。 在您的 IDL 與實作中,將任何可觀察集合宣告為 Windows.Foundation.Collections.IVector<IInspectable> 類型。 但請回傳一個實作 Windows.Foundation.Collections.IObservableVector<T> 的物件,其中 T 是您的元素類型。 請參見 XAML 項目控制項;綁定到 C++/WinRT 集合
C++ 編譯器會產生「'MyImplementationType_base<MyImplementationType>':無適當的預設建構碼可用」的錯誤。 當你從具有非平凡構造子的型態衍生出來時,這種情況就可能發生。 你衍生型態的建構子需要傳遞基底型態建構子所需的參數。 關於一個可行的範例,請參見 從具有非平凡構造子的型別推導
C++ 編譯器會產生錯誤:「無法將 'const std::vector<std::wstring,std::allocator<_Ty>>' 轉換為 'const winrt::param::async_iterable<winrt::hstring> &'」。 當你將 std::vector 傳遞給預期接收集合的 Windows 執行階段 API 時,就可能會發生這種情況。 更多資訊請參閱標準 C++ 資料型別及 C++/WinRT。
C++ 編譯器會產生以下錯誤:「無法將 'const std::vector<winrt::hstring,std::allocator<_Ty>>' 轉換為 'const winrt::param::async_iterable<winrt::hstring> &'」。 當你將 `std::vector` 傳遞給預期接收集合的非同步 Windows 執行階段 API,而你既沒有將該 vector 複製給非同步被呼叫端,也沒有將它移交過去時,就可能會發生這種情況。 更多資訊請參閱標準 C++ 資料型別及 C++/WinRT。
開啟專案時,Visual Studio 會跳出錯誤訊息「該專案的應用程式尚未安裝」。 如果你還沒安裝,你需要安裝 Windows 應用程式 SDK C++ 範本和 C++/WinRT Visual Studio 擴充功能(VSIX)(參見 Visual Studio 對 C++/WinRT 的支援)。
Windows 應用程式 認證套件的測試會產生一個錯誤,顯示你的執行時類別「並非源自 Windows 基底類別。所有可組合類別最終都必須源自 Windows 命名空間中的一個型別。」 任何你在應用程式中宣告的執行時類別,若源自基底類別,都稱為 可組合 類別。 可組合類別的最終基底類別必須是源自 Windows.* 或 Microsoft.* 命名空間的型別;例如,Microsoft。UI。Xaml.DependencyObject。 詳見 XAML 控制項;綁定到 C++/WinRT 屬性 以獲取更多細節。
C++ 編譯器會對 EventHandler 或 TypedEventHandler 代理專用化產生「T 必須是 WinRT 型別」錯誤。 可以考慮改用 winrt::delegate<...T>。 請參見 C++/WinRT 中的作者事件
C++ 編譯器會對 Windows 執行階段 非同步操作專用化產生「T 必須是 WinRT 類型」錯誤。 考慮回傳一個平行模式庫(PPL) 任務 。 參見 並發與非同步操作
當你呼叫 winrt::xaml_typename 時,C++ 編譯器會產生「T 必須是 WinRT 類型」的錯誤。 使用帶有 winrt::xaml_typename 的投影型別(例如,使用 BgLabelControlApp::BgLabelControl),而非實作型別(例如,不要使用 BgLabelControlApp::implementation::BgLabelControl)。 請參見 XAML 自訂(模板化)控制項
C++ 編譯器會產生「錯誤 C2220:警告視為錯誤 - 未產生『物件』檔案」。 要麼修正警告,要麼將 C/C++>General>將警告視為錯誤設為 No (/WX-)。
你的應用程式當機是因為在物件被銷毀後,C++/WinRT 物件中的事件處理程式被呼叫。 請參閱 「使用事件處理委派安全地存取 this 指標」
C++ 編譯器會產生「錯誤 C2338:此僅限於弱參考支援」。 你正在要求取得某個型別的弱式參考,而該型別已將 winrt::no_weak_ref 標記結構體作為範本引數傳遞給其基底類別。 請參見 「選擇退出弱參考支援」。
C++ 編譯器會產生「consume_Something: 回傳 'auto' 的函式在定義之前不能使用 請參閱 C3779:為什麼編譯器會顯示「consume_Something:回傳 'auto' 的函式在定義之前無法使用」錯誤?
C++ 連結器產生「錯誤LNK2019:未解決外部符號 請參考為什麼連結器會給我「LNK2019:未解決外部符號」錯誤?
LLVM 與 Clang 工具鏈在搭配 C++/WinRT 使用時會產生錯誤。 我們不支援用於 C++/WinRT 的 LLVM 和 Clang 工具鏈,但如果你想仿效我們在內部的使用方式,那麼你可以嘗試進行類似 Can I use LLVM/Clang to compile with C++/WinRT? 中所述的實驗。
C++ 編譯器會產生「無適當的預設建構碼可用」來表示投影型別。 如果你想延遲執行時類別物件的初始化,或在同一專案中同時使用並實作執行時類別,那你需要呼叫 std::nullptr_t 建構子。 更多資訊請參閱 Consume API with C++/WinRT
C++ 編譯器會產生「錯誤 C3861:'from_abi':識別碼未找到」,以及其他源自 base.h 的錯誤。 如果你使用 Visual Studio 2017(版本 15.8.0 或更新版本),並針對 Windows SDK 版本 10.0.17134.0(Windows 10,版本 1803)設計,可能會遇到此錯誤。 要麼針對較後期(較符合標準)的 Windows SDK 版本,要麼設定專案屬性 C/C++>Language>相容模式:否(同時,若 /permissive- 出現在專案屬性 C/C++>Language>命令列的附加選項中,則刪除該模式)。
C++ 編譯器會產生「錯誤 C2039: 'IUnknown': 不是 '`global namespace''' 的成員」。 請參閱如何將您的 C++/WinRT 專案重新定位到較新版本的 Windows SDK
C++ 連結器會產生「錯誤 LNK2019:函式 _VSDesignerCanUnloadNow@0 中引用的未解析外部符號_WINRT_CanUnloadNow@0 請參閱如何將您的 C++/WinRT 專案重新定位到較新版本的 Windows SDK
建置過程會產生錯誤訊息:C++/WinRT VSIX 不再提供專案建置支援。請新增對 Microsoft.Windows.CppWinRT NuGet 套件的專案參考。 Microsoft.Windows.CppWinRT NuGet 套件安裝到您的專案中。 詳情請參見 VSIX 擴充的早期版本
C++ 連結器產生 錯誤 LNK2019: 未解決外部符號,並提及 winrt::impl::consume_Windows_Foundation_Collections_IVector C++/WinRT 2.0 起,如果你對 Windows 執行階段 集合使用範圍式 for,那麼現在你就需要 #include <winrt/Windows.Foundation.Collections.h>
C++ 編譯器會產生「錯誤 C4002:函式類巨集呼叫 GetCurrentTime 的參數過多」。 請參考如何用 GetCurrentTime 和/或 TRY 解決歧義。
C++ 編譯器會產生「錯誤 C2334:在 '{' 前出現意外標記;跳過表觀功能體」。 請參考如何用 GetCurrentTime 和/或 TRY 解決歧義。
C++ 編譯器會產生「winrt::impl::p roduce<D,I> Cannot 實例化抽象類別,因為缺少 GetBindingConnector」。 你需要#include <winrt/Microsoft.UI.Xaml.Markup.h>
C++ 編譯器會產生「錯誤 C2039: 'promise_type': is not a member of 'std::experimental::coroutine_traits<void>'」。 你的協程需要回傳一個非同步操作物件,或是 winrt::fire_and_forget。 參見 並發與非同步操作
你的專案產生了「『PopulatePropertyInfoOverride』的模糊存取」。 這個錯誤可能發生在你在 IDL 中宣告一個基底類別,而在 XAML 標記中宣告另一個基底類別時。
首次載入 C++/WinRT 解決方案時,會出現「專案 'MyProject.vcxproj' 配置 'Debug|x86' 的設計建置失敗。IntelliSense 可能無法使用。」 這個 IntelliSense 的問題會在你第一次組裝後解決。
在註冊委派時嘗試指定 winrt::auto_revoke 會引發 winrt::hresult_no_interface 例外狀況。 請參閱 如果您的自動撤銷代理無法註冊
在 C++/WinRT 應用程式中,當使用 XAML 的 C# Windows 執行階段 元件時,編譯器會產生類似「'MyNamespace_XamlTypeInfo': is not a member of 'winrt::MyNamespace'」的錯誤——其中 MyNamespace 是Windows 執行階段該元件的命名空間名稱。 在正在使用中的 C++/WinRT 應用程式中 pch.h ,新增 #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h>—,並適當替換 MyNamespace
在 Visual Studio 的 C++/WinRT 專案中,IntelliSense 會產生一個錯誤,形式為「error E1696: cannot 開放原始碼 file」。 至少編譯你新建立的專案一次。 然後在原始碼編輯器>中右鍵點擊 Rescan>Rescan File。 這將解決所有 IntelliSense 錯誤,包括 E1696。

Note

如果這個主題還沒回答到你的問題,你可以去 Visual Studio C++ 開發者社群,或在 Stack Overflow 上使用這個c++-winrt標籤來獲得幫助。

Note

許多 C++/WinRT 主題正從 UWP 文件遷移到此區。 在遷移完成前,以下列表中的連結可能會導向 UWP 文件區塊。 C++/WinRT 語言投影在 UWP 與 WinUI 3 應用程式中相同,因此內容適用於兩種情境。 任何 UWP 專屬的模式(例如應用程式生命週期或 Windows.UI 命名空間 API)都會在這些文章中明確標示。