C++/WinRT 问题疑难解答

注释

有关安装和使用 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::wstring 的 std::vector 传递给需要集合的 Windows 运行时 API 时,可能会发生这种情况。 有关详细信息,请参阅 标准 C++ 数据类型和 C++/WinRT
C++ 编译器产生错误“无法从 'const std::vector<winrt::hstring,std::allocator<_Ty>>' 转换为 'const winrt::param::async_iterable<winrt::hstring> &'”。 将 winrt::hstring 的 std::vector 传递给需要一个集合的异步 Windows 运行时 API 时,如果没有将相应的矢量复制或移动到异步被调用方,就会出现此错误。 有关详细信息,请参阅 标准 C++ 数据类型和 C++/WinRT
打开项目时,Visual Studio生成错误“未安装项目的应用程序”。 如果尚未安装,则需要安装 Windows 应用 SDK C++ 模板和 C++/WinRT Visual Studio 扩展(VSIX)(请参阅 C++/WinRT Visual Studio支持)。
Windows 应用认证工具包测试生成一个错误,即其中一个运行时类“不派生自Windows基类。所有可组合类最终都必须从Windows命名空间中的类型派生”。 派生自基类的任何运行时类(在应用程序中声明)称为 可组合 类。 可组合类的最终基类必须是源自 Windows.* 或 Microsoft.* 命名空间的类型;例如,Microsoft。UI。Xaml.DependencyObject。 有关详细信息,请参阅 XAML 控件;绑定到 C++/WinRT 属性
对于 EventHandler 或 TypedEventHandler 委托特化,C++ 编译器会产生“T 必须是 WinRT 类型”错误。 请考虑改用 winrt::delegate<...T>。 请参阅 C++/WinRT 中的 Author 事件
对于 Windows 运行时 异步操作特化,C++ 编译器会产生“T 必须为 WinRT 类型”错误。 请考虑改为返回并行模式库(PPL) 任务。 请参阅 并发和异步操作
调用 winrt::xaml_typename时,C++ 编译器将生成“T 必须为 WinRT 类型”错误。 请将投影类型与 winrt::xaml_typename 配合使用(例如,使用 BgLabelControlApp::BgLabelControl),而不是实现类型(例如,不要使用 BgLabelControlApp::implementation::BgLabelControl)。 请参阅 XAML 自定义(模板化)控件
C++ 编译器生成“错误 C2220:警告被视为错误 - 未生成'object'文件”。 更正警告,或将 C/C++>常规>将警告视为错误设置为“否”(/WX-)。
应用崩溃,因为 C++/WinRT 对象中的事件处理程序在对象被销毁后调用。 请参阅使用事件处理委托安全访问该指针
C++ 编译器生成“错误 C2338:这仅适用于弱 ref 支持”。 你请求针对某个类型的弱引用,该类型将“winrt::no_weak_ref”标记结构作为模板参数传递给其基类。 请参阅停用弱引用支持
C++ 编译器给出“consume_Something:返回 'auto' 的函数在其定义之前不能使用 请参阅 C3779:为什么编译器会报出“consume_Something: 返回‘auto’的函数在定义之前无法使用”错误?
C++ 链接器生成“错误LNK2019:未解析的外部符号 请参阅为什么链接器会提示“LNK2019: 无法解析的外部符号”错误?
LLVM 和 Clang 工具链在与 C++/WinRT 一起使用时生成错误。 我们不支持适用于 C++/WinRT 的 LLVM 和 Clang 工具链,但如果想要模拟如何在内部使用它,则可以尝试试验,例如,是否可以使用 LLVM/Clang 进行 C++/WinRT 编译?
C++ 编译器为投影类型生成“没有可用的适当默认构造函数”。 如果尝试延迟运行时类对象的初始化,或者在同一项目中使用和实现运行时类,则需要调用 std::nullptr_t 构造函数。 有关详细信息,请参阅 使用 C++/WinRT 的 API
C++ 编译器生成“error C3861: 'from_abi': identifier not found”,以及源自 base.h 的其他错误。 如果使用 Visual Studio 2017(版本 15.8.0 或更高版本),并且面向 Windows SDK 版本 10.0.17134.0(Windows 10版本 1803),则可能会出现此错误。 要么面向更高版本的 Windows SDK,要么设置项目属性 C/C++>语言>一致性模式:否(如果 /permissive - 出现在项目属性 C/C++>语言>命令行中的“其他选项”下,请将其删除)。
C++ 编译器生成“error C2039:”IUnknown“:不是”全局命名空间“的成员 请参阅如何将 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::produce<D,I> 无法实例化抽象类,原因是缺少 GetBindingConnector”。 你需要 #include <winrt/Microsoft.UI.Xaml.Markup.h>
C++ 编译器生成“error C2039: 'promise_type':不是 '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 会产生如下形式的错误:“错误 E1696: 无法打开源文件”。 至少编译一次新创建的项目。 然后在源代码编辑器>中右键单击“重新扫描>文件”。 这将解决所有 IntelliSense 错误,包括 E1696。

注释

如果本主题未回答你的问题,则可以通过访问 Visual Studio C++ 开发人员社区或使用 c++-winrt Stack Overflow 上的标记找到帮助。

注释

许多 C++/WinRT 主题正在从 UWP 文档迁移到本部分。 在迁移完成前,以下列表中的链接可能会指向 UWP 文档部分。 对于 UWP 和 WinUI 3 应用,C++/WinRT 语言投影是相同的,因此内容适用于这两种上下文。 这些文章中明确指出了任何特定于 UWP 的模式(如应用生命周期或 Windows.UI 命名空间 API)。