编写供 C++/WinRT 应用使用的 C# Windows 运行时 组件

本主题指导你完成将简单的 C# 组件添加到 C++/WinRT 项目的过程。

Visual Studio可以轻松地在用 C# 或 Visual Basic 编写的Windows 运行时组件 (WRC) 项目中创作和部署自己的自定义Windows 运行时类型,然后从 C++ 应用程序项目引用该 WRC,并从该应用程序使用这些自定义类型。

在内部实现中,你定义的 Windows 运行时 类型可以使用 UWP 应用中允许使用的任何 .NET 功能。

在外部,类型的成员只能公开其参数和返回值的Windows 运行时类型。 生成解决方案时,Visual Studio生成 .NET WRC 项目,然后执行创建Windows元数据(.winmd)文件的生成步骤。 这是你的 Windows 运行时组件(WRC),Visual Studio 会将其包含在你的应用中。

注释

.NET自动将一些常用的.NET类型(如基元数据类型和集合类型)映射到其Windows 运行时等效类型。 这些 .NET 类型可用于 Windows 运行时 组件的公开接口中,并且对于该组件的用户来说,它们将显示为相应的 Windows 运行时 类型。 请参阅使用 C# 和 Visual Basic 的 Windows 运行时 组件

先决条件

创建空白应用

在Visual Studio中,使用空白应用(C++/WinRT)项目模板(对于 WinUI 3 桌面应用,使用空白应用打包(桌面版中的 WinUI 3)模板创建新项目。 请确保使用的是 (C++/WinRT) 模板,而不是 (通用Windows) 模板。

将新项目的名称设置为 CppToCSharpWinRT ,以便文件夹结构与演练匹配。

将 C# Windows 运行时 组件添加到解决方案

在 Visual Studio 中创建组件project:在 解决方案资源管理器 中,打开 CppToCSharpWinRT 解决方案的快捷菜单,然后选择“添加”,然后选择“新建Project向解决方案添加新的 C# project。 在“添加新Project”对话框的“已安装的模板”部分中,选择“Visual C#”,然后选择“Windows”,然后选择“通用”。 选择Windows 运行时 组件(通用 Windows)模板,然后在项目名称中输入SampleComponent

注释

在“新建通用 Windows 平台项目”对话框中,选择 Windows 10 创意者更新版(10.0;内部版本 15063) 作为最低版本。 有关详细信息,请参阅下面的 “应用程序最低版本” 部分。

添加 C# GetMyString 方法

SampleComponent 项目中,将类的名称从 Class1 更改为 Example。 然后将两个简单成员添加到类,一个私有 int 字段和一个名为 GetMyString 的实例方法:

    public sealed class Example
    {
        int MyNumber;

        public string GetMyString()
        {
            return $"This is call #: {++MyNumber}";
        }
    }

注释

默认情况下,该类标记为 公共密封。 你从组件中公开的所有 Windows 运行时 类都必须是密封的。

注释

可选:若要为新添加的成员启用 IntelliSense,请在解决方案资源管理器中打开 SampleComponent 项目的快捷菜单,然后选择“生成”。

引用 CppToCSharpWinRT 项目中的 C# SampleComponent

在 解决方案资源管理器 中,在 C++/WinRT 项目中,打开引用的快捷菜单,然后选择“添加引用”以打开“添加引用”对话框。 选择 “项目”,然后选择“ 解决方案”。 选中 SampleComponent 项目的复选框,然后选择 “确定 ”添加引用。

注释

可选:若要为 C++/WinRT 项目启用 IntelliSense,请在解决方案资源管理器中打开 CppToCSharpWinRT 项目的快捷菜单,然后选择“生成”。

编辑 MainPage.h

MainPage.h 项目中打开,然后添加两个项目。 首先在语句末尾#include "winrt/SampleComponent.h"添加#include一个字段,然后将字段winrt::SampleComponent::Example添加到MainPage结构中。

// MainPage.h
...
#include "winrt/SampleComponent.h"

namespace winrt::CppToCSharpWinRT::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
...
        winrt::SampleComponent::Example myExample;
...
    };
}

注释

在Visual Studio中,MainPage.h列在下方MainPage.xaml

编辑MainPage.cpp

MainPage.cpp中,更改 Mainpage::ClickHandler 实现以调用 C# 方法 GetMyString

void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    //myButton().Content(box_value(L"Clicked"));

    hstring myString = myExample.GetMyString();

    myButton().Content(box_value(myString));
}

运行项目

现在可以生成并运行项目。 每次单击该按钮时,按钮中的数字都会递增。

C++/WinRT Windows调用 C# 组件屏幕截图

Tip

在Visual Studio中创建组件项目:在解决方案资源管理器中,打开 CppToCSharpWinRT 项目的快捷菜单,然后选择“属性”,然后选择“配置属性”下的“调试”。 如果要同时调试 C#(托管)和 C++(本机)代码,请将“调试器类型”设置为 托管和本机C++ 调试属性

应用程序最低版本

C# 项目版本的应用程序最低版本将控制用于编译应用程序的.NET的版本。 例如,选择 Windows 10 Fall Creators Update(10.0;内部版本 16299) 或更高版本将启用 .NET Standard 2.0 和对 Windows Arm64 处理器的支持。

Tip

如果不需要 .NET Standard 2.0 或 Arm64 支持,建议使用低于 16299 的应用程序最低版本来避免额外的生成配置。

为 Windows 10 Fall Creators Update(10.0;内部版本 16299)进行配置

按照以下步骤在 C++/WinRT 项目引用的 C# 项目中启用 .NET Standard 2.0 或 Windows Arm64 支持。

在Visual Studio中,转到解决方案资源管理器并打开 CppToCSharpWinRT 项目的快捷菜单。 选择“属性”并将通用Windows 应用最小版本设置为“Windows 10 Fall Creators Update(10.0;内部版本 16299)(或更高版本)。 对 SampleComponent 项目执行相同的操作。

在Visual Studio中,打开 CppToCSharpWinRT project的快捷菜单,然后选择“卸载”Project在文本编辑器中打开CppToCSharpWinRT.vcxproj

将以下 XML 复制并粘贴到 CPPWinRTCSharpV2.vcxproj 中的第一个 PropertyGroup 处。

   <!-- Start Custom .NET Native properties -->
   <DotNetNativeVersion>2.2.12-rel-31116-00</DotNetNativeVersion>
   <DotNetNativeSharedLibrary>2.2.8-rel-31116-00</DotNetNativeSharedLibrary>
   <UWPCoreRuntimeSdkVersion>2.2.14</UWPCoreRuntimeSdkVersion>
   <!--<NugetPath>$(USERPROFILE)\.nuget\packages</NugetPath>-->
   <NugetPath>$(ProgramFiles)\Microsoft SDKs\UWPNuGetPackages</NugetPath>
   <!-- End Custom .NET Native properties -->

DotNetNativeVersionDotNetNativeSharedLibraryUWPCoreRuntimeSdkVersion 的值可能会因 Visual Studio 的版本而异。 若要将其设置为正确的值,请打开 %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages,然后查看下表中每个值对应的子目录。 %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler目录中将有一个子目录,其中包含一个已安装的、以2.2开头的 .NET Native 版本。 在下面的示例中,它是 2.2.12-rel-31116-00

MSBuild 变量 目录 示例
DotNetNativeVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler 2.2.12-rel-31116-00
DotNetNativeSharedLibrary %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x64.microsoft.net.native.sharedlibrary 2.2.8-rel-31116-00
UWPCoreRuntimeSdkVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.UWPCoreRuntimeSdk 2.2.14

注释

Microsoft.Net.Native.SharedLibrary 支持多种架构。 将 x64 替换为适当的体系结构。 例如,体系结构 arm64 将位于 %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64.microsoft.net.native.sharedlibrary 目录中。

接下来,紧接在第一个 PropertyGroup之后,添加以下内容(原样)。

  <!-- Start Custom .NET Native targets -->
  <!-- Import all of the .NET Native / CoreCLR props at the beginning of the project -->
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x86.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x64.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm64.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary.props" />
  <!-- End Custom .NET Native targets -->

在项目文件的末尾、紧靠闭合 Project 标记之前,添加以下内容(保持不变)。

  <!-- Import all of the .NET Native / CoreCLR targets at the end of the project -->
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x86.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x64.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm64.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary.targets" />
  <!-- End Custom .NET Native targets -->

在Visual Studio中重新加载项目文件。 为此,请在Visual Studio 解决方案资源管理器中打开 CppToCSharpWinRT project的快捷菜单,然后选择“重载Project”。

为 .NET Native 构建

建议使用基于本机.NET生成的 C# 组件生成和测试应用程序。 在Visual Studio中,打开 CppToCSharpWinRT project的快捷菜单,然后选择“卸载”Project在文本编辑器中打开CppToCSharpWinRT.vcxproj

接下来,将 UseDotNetNativeToolchain 属性设置为 true C++ 项目文件中的 Release 和 Arm64 配置。

在Visual Studio 解决方案资源管理器中,打开 CppToCSharpWinRT project的快捷菜单,然后选择“重载Project”。

  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
...
    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Platform)'=='Arm64'" Label="Configuration">
    <UseDotNetNativeToolchain Condition="'$(UseDotNetNativeToolchain)'==''">true</UseDotNetNativeToolchain>
  </PropertyGroup>

引用其他 C# NuGet 包

如果 C# 组件引用其他 nuget 包,则应用程序的项目文件可能需要将 nuget 包中的文件依赖项作为部署内容列出。 例如,如果 C# 组件引用 Newtonsoft.Json nuget 包,则应用程序项目中还应引用相同的 nuget 包和文件依赖项。

SampleComponent.csproj 文件中,添加 nuget 包引用:

    <PackageReference Include="Newtonsoft.Json">
      <Version>13.0.1</Version>
    </PackageReference>

CppToCSharpWinRT 项目中,找到 packages.config 文件并添加相应的 nuget 引用。 这会将 nuget 包安装到解决方案的包文件夹中。

packages.config中,添加相同的 nuget 包引用:

  <package id="Newtonsoft.Json" version="13.0.1" targetFramework="native" developmentDependency="true" />

然后将以下内容添加到应用程序项目文件,以引用解决方案包文件夹中的相应文件依赖项。 例如,在 CppToCSharpWinRT.vcxproj 中添加以下内容:

  <ItemGroup>
    <None Include="..\packages\Newtonsoft.Json.13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll">
      <Link>%(Filename)%(Extension)</Link>
      <DeploymentContent>true</DeploymentContent>
    </None>
  </ItemGroup>