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

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

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

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

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

Note

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

Необходимые условия

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

В Visual Studio создайте новый проект, используя шаблон проекта Blank App (C++/WinRT) (для настольных приложений WinUI 3 используйте шаблон Blank App, Packaged (WinUI 3 in Desktop)). Убедитесь, что вы используете шаблон (C++/WinRT), а не (Универсальная платформа Windows).

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

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

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

Note

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

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

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

    public sealed class Example
    {
        int MyNumber;

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

Note

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

Note

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

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

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

Note

Необязательно. Чтобы включить 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;
...
    };
}

Note

В 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# из C++/WinRT Windows

Подсказка

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

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

Минимальная версия проекта 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 или Windows Arm64 в проектах C#, на которые ссылается проект C++/WinRT.

В Visual Studio перейдите к Обозреватель решений и откройте контекстное меню для проекта CppToCSharpWinRT. Выберите Properties и задайте для минимальной версии Universal приложение для Windows значение Windows 10 Fall Creators Update (10.0; сборка 16299) (или более позднюю). Выполните то же самое для проекта SampleComponent .

В Visual Studio откройте контекстное меню для project CppToCSharpWinRT и выберите "Выгрузить Project", чтобы открыть 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 будет подкаталог, имя которого начинается с 2.2 и в котором содержится установленная версия .NET Native. В приведенном ниже примере это 2.2.12-rel-31116-00.

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

Note

Существует несколько поддерживаемых архитектур для 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 Обозреватель решений откройте контекстное меню для project CppToCSharpWinRT и выберите "Перезагрузить Project".

Сборка для .NET Native

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

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

В Visual Studio Обозреватель решений откройте контекстное меню для project CppToCSharpWinRT и выберите "Перезагрузить Project".

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