创作用于C++/WinRT 应用的 C# Windows 运行时组件

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

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

在内部,Windows 运行时类型可以使用 UWP 应用程序中允许的任何 .NET 功能。

注释

有关详细信息,请参阅 Windows 运行时组件与 C# 和 Visual Basic,以及 用于 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) 项目模板创建新项目。 请确保使用的是 (C++/WinRT) 模板,而不是 (通用 Windows) 模板。

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

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

在 Visual Studio 中创建组件项目:在解决方案资源管理器中,打开 CppToCSharpWinRT 解决方案的快捷菜单,然后选择 “添加”,然后选择 “新建项目 ”以向解决方案添加新的 C# 项目。 在“添加新项目”对话框的“已安装模板”部分中,选择“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

CppToCSharpWinRT 项目中打开MainPage.h,然后添加两个项目。 首先在语句末尾#include添加#include "winrt/SampleComponent.h"一个字段,然后将字段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.hMainPage.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# 组件屏幕截图

小窍门

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

应用程序最低版本

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

小窍门

如果不需要 .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 项目的快捷菜单,然后选择 卸载项目 在文本编辑器中打开 CppToCSharpWinRT.vcxproj

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

   <!-- 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 本机版本。 在下面的示例中,它是 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 项目的快捷菜单,然后选择 “重载项目”。

构建 .NET Native

建议在 .NET native 下生成的 C# 组件上构建和测试您的应用程序。 在 Visual Studio 中,打开 CppToCSharpWinRT 项目的快捷菜单,然后选择 卸载项目 在文本编辑器中打开 CppToCSharpWinRT.vcxproj

接下来,在C++项目文件的“发布”和“Arm64”配置中将UseDotNetNativeToolchain属性设置为true

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

  <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>