C++/CX和C++/WinRT可以在同一个项目中使用吗?

IIn*_*ble 12 c++ windows-runtime c++-cx win-universal-app c++-winrt

本周早些时候,Kenny Kerr 在CppCon 2016 1上展示了C++/WinRT.它是基于Modern的Windows Runtime的标准C++投影.

据我所知,C++/CX编译器/预处理器/代码生成器不接触标准C++代码,而C++/WinRT是标准C++库,这是我天真的解释,C++/CX和C++/WinRT都可以在同一个项目中使用.

问题:

  • 第一件事:我天真的解释是否正确?
  • 如果是这样,C++/CX和C++/WinRT可以在同一个编译单元中使用吗?
  • C++/CX和C++/WinRT的粒度可以混合在一起,以防它们不能驻留在同一个编译单元中?
  • C++/WinRT可以在同一个项目中使用C++/CX实现的类型吗?(我希望这很困难,因为C++/WinRT编译器需要从.winmd元数据生成头,因此依赖于(预)编译器输出.)

如果重要的话,那些问题的答案让我现在可以决定如何将我的C++/CX项目推向未来.


1 为Windows运行时使用标准C++(在YouTube上).

Ken*_*err 14

简而言之,是的,C++/CX和C++/WinRT可以在同一个项目中使用.

C++/CX编译器将Winmd类型注入根命名空间.C++/WinRT将所有内容包装在其自己的根winrt命名空间中,以适应与C++/CX的互操作,并避免与其他库的C++编译器模糊错误.所以下面的C++/CX代码:

using namespace Windows::Foundation;
using namespace Windows::Networking;

Uri ^ uri = ref new Uri(L"https://moderncpp.com/");
HostName ^ name = ref new HostName(L"moderncpp.com");
Run Code Online (Sandbox Code Playgroud)

可以用C++/WinRT重写如下:

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Networking;

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");
Run Code Online (Sandbox Code Playgroud)

或者,如果您正在使用/ ZW进行编译,那么您可以按如下方式重写它(以避免错误C2872:'Windows':模糊符号):

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Networking;

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");
Run Code Online (Sandbox Code Playgroud)

您可以将C++/CX和C++/WinRT组合在同一源文件中的另一种方法是使用根命名空间,如下所示:

namespace cx
{
    using namespace Windows::Foundation;
    using namespace Windows::Networking;
}

namespace winrt
{
    using namespace Windows::Foundation;
    using namespace Windows::Networking;
}

void Sample()
{
    cx::Uri uri(L"https://moderncpp.com/");
    winrt::HostName name(L"moderncpp.com");
}
Run Code Online (Sandbox Code Playgroud)

在一天结束时,C++/WinRT只是一个标准的C++库,您可以将其包含在任何适用的C++项目中.但是,C++/CX和C++/WinRT确实以非常不同的方式处理元数据.C++/CX直接消耗和生成元数据,而C++/WinRT受标准C++的约束,因此需要一个独立的工具(cppwinrt.exe)来帮助弥合这一差距.


Bre*_*tor 3

关于“C++/WinRT 能否使用在同一项目中使用 C++/CX 实现的类型?”这一问题

答案是“是”和“否”。在同一项目中定义“引用类”时,由于此类项目必须在启用 C++/CX 的情况下进行编译,因此您的代码可以像使用任何引用类一样简单地使用该类。

但是,如果您想将“ref 类”用作 C++/WinRT 投影,答案实际上是否定的。

为了获取 C++/WinRT 投影类定义,需要对“引用类”的元数据运行 cppwinrt.exe 编译器。这需要以某种方式获取元数据。您可以设置某种机制来编译“引用类”一次,获取 winmd,通过 mdmerge 对其进行处理以将其置于规范形式,在元数据上运行 cppwinrt.exe 以获取预计的类定义,然后包含生成的标头。

或者,您可以编写 IDL 来描述“ref 类”,使用 MIDLRT 将其编译为元数据,然后运行 ​​cppwinrt.exe。IMO 两者都不实用。

最合理的替代方案是简单地使用 ref 类作为 C++/CX 类型,因为定义位于同一解决方案中。下一个最实用的解决方案是将类放在一个单独的项目中,编译它并获取 winmd,然后从 winmd 创建标头。这种方法还允许在不使用 C++/CX 代码的情况下构建使用“引用类”(通过投影)的单独项目。

为了完全透明,请注意,我们的初始版本(现已在https://github.com/Microsoft/cppwinrt提供)不包含 cppwinrt.exe 编译器本身。相反,它包含 C++/WinRT 头文件,其中包含 Windows 10 周年更新 SDK 中定义的所有 Windows 运行时类型/API 的投影 - 这包括通用平台 API 和所有扩展 SDK API。