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

Can C++/CX and C++/WinRT be used in the same project?

本周早些时候,肯尼·科尔 presented C++/WinRT at CppCon 20161. It is a Standard C++ projection for the Windows Runtime, based on Modern

据我所知,C++/CX compiler/preprocessor/code 生成器不涉及标准 C++ 代码,并且 C++/WinRT 是标准 C++ 库,这是我天真的解释,即 C++ /CX 和 C++/WinRT 可以在同一个项目中使用。

问题:

以防万一,这些问题的答案让我现在就可以决定如何将我的 C++/CX 项目转移到未来。


1 Embracing Standard C++ for the Windows Runtime (on YouTube).

简短的回答是可以在同一个项目中使用 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");

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

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

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");

或者,如果您使用 /ZW 进行编译,则可以按如下方式重写它(以避免错误 C2872:'Windows':符号不明确):

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

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");

在同一个源文件中组合 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");
}

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

关于问题"Can C++/WinRT consume types implemented with C++/CX in the same project?"

答案是肯定的,也不是。在同一个项目中定义了 'ref class',因为这样的项目必须在启用 C++/CX 的情况下编译,您的代码可以简单地使用 class 作为它可以是任何参考 class.

但是,如果您想将 'ref class' 作为 C++/WinRT 投影使用,答案实际上是否定的。

为了获得 C++/WinRT 投影的 class 定义,您需要 运行 cppwinrt.exe 编译器处理 'ref class' 的元数据。这将需要以某种方式获取元数据。您可以设置一些机制来编译 'ref class' 一次,获取 winmd,通过 mdmerge 处理它以将其置于规范形式,运行 cppwinrt.exe 在元数据上获得投影 class定义,然后包含生成的headers.

或者,您可以编写 IDL 来描述 'ref class',使用 MIDLRT 将其编译为元数据,然后 运行 cppwinrt.exe。 IMO 也不实用。

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

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