Création d’un composant Windows Runtime C# à utiliser à partir d’une application C++/WinRT

Cette rubrique vous montre pas à pas comment ajouter un composant C# simple à un projet C++/WinRT.

Visual Studio vous aide à créer et déployer vos propres types Windows Runtime personnalisés dans un projet de composant Windows Runtime (WRC) écrit en C# ou Visual Basic, puis à référencer ce WRC à partir d’un projet d’application C++ et à utiliser ces types personnalisés dans cette application.

En interne, vos types Windows Runtime peuvent utiliser toutes les fonctionnalités .NET qui sont autorisées dans une application Windows universelle (UWP).

En externe, les membres de votre type peuvent exposer uniquement les types Windows Runtime pour leurs paramètres et valeurs de retour. Quand vous générez votre solution, Visual Studio génère votre projet .NET WRC, puis exécute une étape de génération qui crée un fichier de métadonnées Windows (.winmd). Il s’agit de votre composant Windows Runtime (WRC), que Visual Studio inclut dans votre application.

Notes

.NET mappe automatiquement certains types .NET couramment utilisés, tels que les types de données primitifs et les types de collection, à leurs équivalents Windows Runtime. Ces types .NET peuvent être utilisés dans l’interface publique d’un composant Windows Runtime et sont présentés aux utilisateurs du composant comme les types Windows Runtime correspondants. Consultez Composants Windows Runtime avec C# et Visual Basic.

Prérequis

Créer une application vide

Dans Visual Studio, créez un projet à l’aide du modèle de projet Blank App (C++/WinRT) . Veillez à utiliser le modèle (C++/WinRT) , et non le modèle (Windows universel) .

Nommez le nouveau projet CppToCSharpWinRT afin que votre structure de dossiers corresponde à la procédure pas à pas.

Ajouter un composant Windows Runtime C# à la solution

Dans Visual Studio, créez le projet de composant : dans l’Explorateur de solutions, ouvrez le menu contextuel de la solution CppToCSharpWinRT. Ensuite, choisissez Ajouter, puis Nouveau projet pour ajouter un nouveau projet C# à la solution. Dans la section Modèles installés de la boîte de dialogue Ajouter un nouveau projet, choisissez Visual C# , puis choisissez Windows et Universel. Choisissez le modèle Composant Windows Runtime (Universal Windows) et nommez le projet SampleComponent.

Notes

Dans la boîte de dialogue Nouveau projet de plateforme Windows universelle, choisissez Windows 10 Creators Update (10.0 ; Build 15063) comme version minimale. Pour plus d’informations, consultez la section Version minimale de l’application ci-dessous.

Ajouter la méthode GetMyString C#

Dans le projet SampleComponent, changez le nom de la classe de Class1 en Example. Ajoutez ensuite deux membres simples à la classe, un champ int privé et une méthode d’instance nommée GetMyString :

    public sealed class Example
    {
        int MyNumber;

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

Notes

Par défaut, la classe est marquée comme public sealed. Toutes les classes Windows Runtime que vous exposez à partir de votre composant doivent être sealed.

Notes

Facultatif : pour activer IntelliSense pour les membres récemment ajoutés, dans l’Explorateur de solutions, ouvrez le menu contextuel du projet SampleComponent, puis choisissez Générer.

Référencer le SampleComponent C# à partir du projet CppToCSharpWinRT

Dans l’Explorateur de solutions, dans le projet C++/WinRT, ouvrez le menu contextuel de Références, puis choisissez Ajouter une référence pour ouvrir la boîte de dialogue Ajouter une référence. Sélectionnez Projets, puis Solution. Cochez la case du projet SampleComponent et choisissez OK pour ajouter une référence.

Notes

Facultatif : pour activer IntelliSense pour le projet C++/WinRT, dans l’Explorateur de solutions, ouvrez le menu contextuel du projet CppToCSharpWinRT, puis choisissez Générer.

Modifier MainPage.h

Ouvrez MainPage.h dans le projet CppToCSharpWinRT, puis ajoutez deux éléments. Ajoutez tout d’abord #include "winrt/SampleComponent.h" à la fin des instructions #include, puis ajoutez un champ winrt::SampleComponent::Example à la structure MainPage.

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

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

Notes

Dans Visual Studio, MainPage.h est listé sous MainPage.xaml.

Modifier MainPage.cpp

Dans MainPage.cpp, modifiez l’implémentation de Mainpage::ClickHandler pour appeler la méthode C# GetMyString.

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

    hstring myString = myExample.GetMyString();

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

Exécuter le projet

Vous pouvez à présent lancer le processus de génération et exécuter le projet. Chaque fois que vous cliquez sur le bouton, le nombre sur le bouton est incrémenté.

C++/WinRT Windows calling into a C# component screenshot

Astuce

Dans Visual Studio, créez le projet de composant : dans l’Explorateur de solutions, ouvrez le menu contextuel du projet CppToCSharpWinRT. Ensuite, choisissez Propriétés, puis choisissez Débogage sous Propriétés de configuration. Définissez le type de débogueur sur Managé et natif si vous souhaitez déboguer à la fois le code C# (managé) et le code C++ (natif). C++ Debugging Properties

Version minimale de l’application

La version minimale de l’application du projet C# contrôlera la version de .NET utilisée pour compiler l’application. Par exemple, le choix de Windows 10 Fall Creators Update (10.0 ; Build 16299) ou ultérieur permettra la prise en charge des processeurs NET Standard 2.0 et Windows Arm64.

Conseil

Nous vous recommandons d’utiliser des versions minimales d’application antérieures à la build 16299 pour éviter une configuration de build supplémentaire si la prise en charge de .NET Standard 2.0 ou Arm64 n’est pas nécessaire.

Configurer pour Windows 10 Fall Creators Update (10.0 ; Build 16299)

Effectuez les étapes suivantes pour activer la prise en charge de .NET Standard 2.0 ou Windows Arm64 dans les projets C# référencés à partir de votre projet C++/WinRT.

Dans Visual Studio, accédez à l’Explorateur de solutions et ouvrez le menu contextuel du projet CppToCSharpWinRT. Choisissez Propriétés et définissez la version minimale de l’application Windows universelle sur Windows 10 Fall Creators Update (10.0 ; Build 16299) (ou une version ultérieure). Faites la même chose pour le projet SampleComponent.

Dans Visual Studio, ouvrez le menu contextuel du projet CppToCSharpWinRT et choisissez Décharger le projet pour ouvrir CppToCSharpWinRT.vcxproj dans l’éditeur de texte.

Copiez et collez le code XML suivant dans le premier PropertyGroup dans 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 -->

Les valeurs de DotNetNativeVersion, DotNetNativeSharedLibrary et UWPCoreRuntimeSdkVersion peuvent varier selon la version de Visual Studio. Pour attribuer les valeurs correctes, ouvrez %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages et examinez le sous-répertoire pour chaque valeur dans le tableau ci-dessous. Le répertoire %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler contient un sous-répertoire qui contient lui-même une version installée de .NET Native qui commence par 2.2. Dans l’exemple ci-dessous, c’est 2.2.12-rel-31116-00.

Variable MSBuild Répertoire Exemple
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

Notes

Il existe plusieurs architectures prises en charge pour Microsoft.Net.Native.SharedLibrary. Remplacez x64 par l’architecture appropriée. Par exemple, l’architecture arm64 se trouverait dans le répertoire %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64.microsoft.net.native.sharedlibrary.

Ensuite, immédiatement après le premier PropertyGroup, ajoutez le code suivant (non modifié).

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

À la fin du fichier projet, juste avant la balise de fermeture Project, ajoutez le code suivant (non modifié).

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

Rechargez le fichier projet dans Visual Studio. Pour ce faire, dans l’Explorateur de solutions Visual Studio, ouvrez le menu contextuel du projet CppToCSharpWinRT et choisissez Recharger le projet.

Génération pour .NET Native

Il est recommandé de générer et de tester votre application avec le nouveau composant C# sur .NET Native. Dans Visual Studio, ouvrez le menu contextuel du projet CppToCSharpWinRT et choisissez Décharger le projet pour ouvrir CppToCSharpWinRT.vcxproj dans l’éditeur de texte.

Ensuite, définissez la propriété UseDotNetNativeToolchain sur la valeur true dans les configurations Release et Arm64 dans le fichier projet C++.

Dans l’Explorateur de solutions Visual Studio, ouvrez le menu contextuel du projet CppToCSharpWinRT et choisissez Recharger le projet.

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

Référencement d’autres packages NuGet C#

Si le composant C# référence d’autres packages NuGet, le fichier projet de l’application peut avoir besoin de lister les dépendances de fichiers du package NuGet en tant que contenu de déploiement. Par exemple, si le composant C# fait référence au package NuGet Newtonsoft.Json, le même package NuGet et la même dépendance de fichier doivent aussi être référencés dans le projet d’application.

Dans le fichier SampleComponent.csproj, ajoutez la référence du package NuGet :

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

Dans le projet CppToCSharpWinRT, recherchez le fichier packages.config et ajoutez la référence NuGet appropriée. Ceci va installer le package NuGet dans le dossier de package de la solution.

Dans packages.config, ajoutez la référence du package NuGet :

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

Ajoutez ensuite ceci au fichier projet de l’application pour référencer la dépendance de fichier appropriée à partir du dossier de package de la solution. Par exemple, dans CppToCSharpWinRT.vcxproj, ajoutez ceci :

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