从 C# 使用 C++/WinRT 组件

Tim*_*son 5 c# windows-runtime c++-cx winrt-component c++-winrt

我有一个用 C++/CX 编写的项目(动态库),该项目由用 C# 编写的 Windows 10 通用应用程序(针对 x86 和 ARM32)使用。
我想将库重写为C++/WinRT,以便使用普通 C++。

问题 1:是否可以创建 C++/WinRT DLL 并从 C# 中使用它?
问题 2:如何设置 C++/WinRT 项目以使其能够从商店应用程序中使用?

Rya*_*erd 4

cppwinrt.exe 编译器于 2017 年 11 月左右开始在Windows Preview SDK中发布。使用它,您可以更轻松地创建自己的 C++/WinRT 组件,以便其他商店应用程序可以使用它。

github 上有一个示例(https://github.com/kennykerr/cppwinrt/tree/master/Store/Component),它针对 C++ 商店应用程序执行此操作。显然,对于 C# 应用程序来说,App 项目需要有所不同,但这应该足以让您入门。特别是,C++/WinRT 组件项目虽然很基本,但包含创建组件所需的大部分魔力。

我们正在积极努力通过项目模板和其他功能使这种体验更加无缝,但目前,您仍然可以通过类似于链接示例的方式来完成此操作,而无需做太多工作。

示例中发生的情况的简短版本是:

  1. 在 IDL 文件中定义组件的 API
  2. 调用 MIDL 将 IDL 编译为元数据 (.winmd)
  3. 调用 cppwinrt.exe 编译器生成脚手架来实现运行时类以及激活所需的 DllGetActivationFactory 挂钩。

想了解正在发生的事情的详细信息吗?

第 1 步:IDL

该示例的 API 非常简单,所以我将其发布在这里。

import "Windows.Foundation.idl";

namespace Component
{
  runtimeclass Button;

  [version(1.0), uuid(461c8806-8bc2-4622-8eac-b547c39f867e), exclusiveto(Button)]
  interface IButton : IInspectable
  {
    [propget] HRESULT Text([out,retval] HSTRING* value);
  };

  [version(2.0), uuid(d3235252-4081-4cc8-b0e0-8c7691813845), exclusiveto(Button)]
  interface IButton2 : IInspectable
  {
      HRESULT Show();
  };

  [version(1.0), activatable(1.0)]
  runtimeclass Button
  {
      [default] interface IButton;
      interface IButton2;
      interface Windows.Foundation.IStringable;
  }
}
Run Code Online (Sandbox Code Playgroud)

第二步:创建winmd

这只需要您将正确的命令行参数传递给 MIDL,可以在 Visual Studio 中看到项目属性和 IDL 文件的属性。您需要的是:

  • 启用 Windows 运行时(添加 /winrt)
  • 添加您的元数据参考目录。如果您的目标是 16299 SDK,则这将是$(FrameworkSdkDir)References\10.0.16299.0\Windows.Foundation.FoundationContract\3.0.0.0. 如果您的目标是不同的 SDK,请适当更新。
  • 设置输出元数据文件。通常最简单的方法是将其设置为$(ProjectName).winmd
  • 将 /nomidl 和 /struct_by_ref 添加到 MIDL 命令行。相信我。

此时,构建项目现在应该会生成一个 winmd 文件。在链接的示例中,它将命名为 Component.winmd。如果需要,您可以使用 ildasm 打开 winmd 并验证它是否包含您的所有内容。

步骤3:

运行 cppwinrt.exe 以生成脚手架。您可以在 Component 项目中看到它有一个 CustomBuildStep 使用一些参数调用 cppwinrt.exe:cppwinrt.exe -in $(ProjectDir)Component.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref 10.0.17061.0 -verbose

  • -in输入 winmd 位置。这是您在步骤 2 中生成的内容。
  • -comp我们在“组件”模式下运行,以便它生成脚手架。
  • -out生成的脚手架放置在哪里。
  • -ref在哪里可以找到您的 winmd 所依赖的输入 winmd。您还可以指定 SDK 版本(这就是此处发生的情况)或-ref local仅使用正在运行的操作系统上的任何版本。使用SDK版本是最干净的。
  • -verbose不言自明。

下载示例项目并试用一下。从那里,希望可以轻松地设置您自己的组件和应用程序。