Разработка компонента среды выполнения Windows C# для использования из приложения C++/WinRT

В этом разделе описывается процесс добавления простого компонента C# в ваш проект C++/WinRT

Visual Studio позволяет легко создавать и развертывать собственные пользовательские типы среды выполнения Windows в проекте компонента среды выполнения Windows (WRC), написанном на C# или Visual Basic, а затем вызывать этот WRC из проекта приложения C++ и использовать пользовательские типы из этого приложения.

На внутреннем уровне типы среды выполнения Windows могут использовать любые функции .NET, разрешенные в приложении UWP.

Снаружи члены разрабатываемого типа могут предоставлять доступ только к параметрам и возвращаемым значениями типов среды выполнения Windows. При построении решения Visual Studio создает проект .NET WRC, а затем выполняет шаг построения, создающий файл метаданных Windows (WinMD). Это компонент среды выполнения Windows (WRC), который Visual Studio включает в приложение.

Примечание.

Платформа .NET автоматически сопоставляет некоторые часто используемые типы .NET, такие как простые типы данных и коллекций, с их эквивалентами среды выполнения Windows. Эти типы .NET можно использовать в общедоступном интерфейсе компонента среды выполнения Windows, и они будут представляться пользователям компонента в виде соответствующих типов среды выполнения Windows. См. Создание компонентов среды выполнения Windows с помощью C# и Visual Basic.

Необходимые компоненты

Создание пустого приложения

В Visual Studio создайте проект с помощью шаблона проекта Пустое приложение (C++/WinRT). Убедитесь, что вы используете шаблон (C++/WinRT), а не (Универсальное приложение для Windows).

Задайте для нового проекта имя CppToCSharpWinRT, чтобы структура папок соответствовала этому пошаговому руководству.

Добавление компонента среды выполнения Windows C# в решение

В Visual Studio создайте проект компонента: в Обозревателе решений откройте контекстное меню решения CppToCSharpWinRT и выберите Добавить, а затем выберите Создать проект, чтобы добавить в решение новый проект C#. В разделе Установленные шаблоны диалогового окна Добавить новый проект выберите Visual C#, после чего выберите Windows, а затем выберите Универсальные. Выберите шаблон Компонент среды выполнения Windows (универсальные приложения для Windows), а в качестве имени проекта укажите SampleComponent.

Примечание.

В диалоговом окне Новый проект приложения для универсальной платформы Windows выберите Обновление Windows 10 Creators Update (10.0; сборка 15063) в качестве минимальной версии. Дополнительные сведения см. в разделе Минимальная версия приложения ниже.

Добавление метода C# GetMyString

В проекте SampleComponent измените имя класса с Class1 на Example. Затем добавьте в класс два простых члена, закрытое поле int и метод экземпляра с именем GetMyString:

    public sealed class Example
    {
        int MyNumber;

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

Примечание.

По умолчанию класс помечен как public sealed. Все классы среды выполнения Windows, доступ к которым предоставляется из компонента, должны быть запечатанными.

Примечание.

Необязательно: чтобы разрешить функции IntelliSense для добавляемых членов, в Обозревателе решений откройте контекстное меню проекта SampleComponent и выберите команду Сборка.

Ссылка на C# SampleComponent из проекта CppToCSharpWinRT

В Обозревателе решений в проекте C++/WinRT откройте контекстное меню для элемента Ссылки и выберите Добавить ссылку, чтобы открыть диалоговое окно Добавление ссылки. Выберите "Проекты" и выберите "Решение". Установите флажок для проекта SampleComponent и нажмите кнопку ОК, чтобы добавить ссылку.

Примечание.

Необязательно. Чтобы включить IntelliSense для проекта C++/WinRT, в обозревателе решений откройте контекстное меню проекта CppToCSharpWinRT, а затем выберите пункт Сборка.

Внесение изменений в файл MainPage.h

Откройте MainPage.h в проекте CppToCSharpWinRT, а затем добавьте два элемента. Сначала добавьте #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 calling into a C# component screenshot

Совет

В Visual Studio создайте проект компонента: в обозревателе решений откройте контекстное меню проекта CppToCSharpWinRT и выберите пункт Свойства, а затем выберите пункт Отладка в разделе Свойства конфигурации. Если требуется выполнить отладку (управляемого) кода C# и (машинного) кода C++, задайте для типа отладчика Управляемый и машинный . C++ Debugging Properties

Минимальная версия приложения

Минимальная версия приложения для версии проекта C# будет управлять версией .NET, используемой для компиляции приложения. Например, выбор Windows 10 Fall Creators Update (10.0; Сборка 16299) или более поздней версии включает поддержку процессора .NET Standard 2.0 и Windows Arm64.

Совет

Рекомендуется использовать минимальные версии приложения ниже 16299, чтобы избежать дополнительной настройки сборки, если не требуется поддержка .NET Standard 2.0 или поддержка процессоров ARM64.

Настройка для Windows 10 Fall Creators Update (10.0; сборка 16299)

Выполните следующие действия, чтобы включить поддержку .NET Standard 2.0 или ARM64 в Windows в проектах C#, упоминаемых в проекте C++/WinRT.

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

Значения для DotNetNativeVersion, DotNetNativeSharedLibrary и UWPCoreRuntimeSdkVersion могут меняться в зависимости от версии Visual Studio. Чтобы задать правильные значения, откройте %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages и просмотрите вложенный каталог для каждого значения в таблице ниже. Каталог %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler будет включать подкаталог, содержащий установленную версию .NET Native, которая начинается с 2.2. В приведенном ниже примере это 2.2.12-rel-31116-00.

Переменная MSBuild Directory Пример
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

Рекомендуется создать и протестировать приложение с помощью компонента C#, созданного на основе .NET Native. В Visual Studio откройте контекстное меню проекта CppToCSharpWinRT и выберите пункт Выгрузить проект, чтобы открыть CppToCSharpWinRT.vcxproj в текстовом редакторе.

Затем присвойте свойству UseDotNetNativeToolchain значение true в конфигурациях Release и ARM64 в файле проекта C++.

В обозревателе решений 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>

Создание ссылок на другие пакеты NuGet C#

Если компонент C# ссылается на другие пакеты NuGet, файлу проекта приложения, возможно, потребуется получить список зависимостей файлов от пакета NuGet в качестве содержимого развертывания. Например, если компонент C# ссылается на пакет NuGet Newtonsoft.Json, в проекте приложения также должны быть ссылки на тот же пакет 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>