Partager via


Générer une projection C# à partir d’un composant C++/WinRT, distribuer en tant qu’application NuGet pour .NET

Dans cette rubrique, nous allons utiliser C#/WinRT pour générer un assembly de projection .NET C# (ou interopérabilité) à partir d’un composant Windows Runtime C++/WinRT et le distribuer en tant que package NuGet pour les applications .NET.

Dans .NET 6 et versions ultérieures, la consommation de fichiers de métadonnées Windows (WinMD) n’est plus prise en charge (voir la prise en charge intégrée de WinRT est supprimée de .NET). Au lieu de cela, l’outil C#/WinRT peut être utilisé pour générer un assembly de projection pour n’importe quel fichier WinMD, qui permet ensuite de consommer des composants WinRT à partir d’applications .NET. Un assembly de projection est également appelé assembly d’interopérabilité. Cette procédure pas à pas vous montre comment effectuer les opérations suivantes :

  • Utilisez le package C#/WinRT pour générer une projection C# à partir d’un composant C++/WinRT.
  • Distribuez le composant, ainsi que l’assembly de projection, en tant que package NuGet.
  • Utilisez le package NuGet à partir d’une application console .NET.

Conditions préalables

Cette procédure pas à pas et l’exemple correspondant nécessitent les outils et composants suivants :

  • Visual Studio 2022 (ou Visual Studio 2019) avec la charge de travail de développement de plateforme Windows universelle installée. Dans les Détails de l’installation>de développement de la plateforme Windows universelle, cochez l’option Outils de la plateforme Windows universelle C++ (v14x).
  • SDK .NET 6.0 ou version ultérieure.

Visual Studio 2019 uniquement. L’extension VSIX C++/WinRT, qui vous donne des modèles de projet C++/WinRT dans Visual Studio. Les modèles de projet sont intégrés à Visual Studio 2022.

Nous allons utiliser Visual Studio 2022 et .NET 6 dans cette procédure pas à pas.

Important

En outre, vous devez télécharger ou cloner l’exemple de code de cette rubrique à partir de l’exemple de projection C#/WinRT sur GitHub. Visitez CsWinRT , puis cliquez sur le bouton vert Code pour obtenir l'url git clone. Veillez à lire le fichier README.md pour l’exemple.

Créer un composant Windows Runtime C++/WinRT simple

Pour suivre cette procédure pas à pas, vous devez d’abord disposer d’un composant Windows Runtime C++/WinRT (WRC) à partir duquel générer l’assembly de projection C#.

Cette procédure pas à pas utilise le SimpleMathComponent WRC à partir de l’exemple de projection C#/WinRT sur GitHub, que vous avez déjà téléchargé ou cloné. SimpleMathComponent a été créé à partir du Windows Runtime Component (C++/WinRT) modèle de projet Visual Studio (fourni avec Visual Studio 2022 ou avec l’extension VSIX C++/WinRT ).

Pour ouvrir le projet SimpleMathComponent dans Visual Studio, ouvrez le \CsWinRT\src\Samples\NetProjectionSample\CppWinRTComponentProjectionSample.sln fichier que vous trouverez dans votre téléchargement ou clone du dépôt.

Le code de ce projet fournit les fonctionnalités des opérations mathématiques de base indiquées dans le fichier d’en-tête ci-dessous.

// SimpleMath.h
...
namespace winrt::SimpleMathComponent::implementation
{
    struct SimpleMath: SimpleMathT<SimpleMath>
    {
        SimpleMath() = default;
        double add(double firstNumber, double secondNumber);
        double subtract(double firstNumber, double secondNumber);
        double multiply(double firstNumber, double secondNumber);
        double divide(double firstNumber, double secondNumber);
    };
}

Vous pouvez confirmer que la propriété Compatible Windows Desktop est définie sur Oui pour le projet de composant Windows Runtime SimpleMathComponent C++/WinRT. Pour ce faire, dans les propriétés du projet pour SimpleMathComponent, sous Propriétés de configuration>Général>Paramètres par défaut du projet, définissez la propriété Compatible avec le bureau Windows sur Oui. Cela garantit que les fichiers binaires du runtime appropriés sont chargés pour consommer des applications de bureau .NET.

page de propriétés compatible Bureau

Pour plus d’informations sur la création d’un composant C++/WinRT et la génération d’un fichier WinMD, consultez les composants Windows Runtime avec C++/WinRT.

Remarque

Si vous implémentez IInspectable::GetRuntimeClassName dans votre composant, il doit retourner un nom de classe WinRT valide. Étant donné que C#/WinRT utilise la chaîne de nom de classe pour l’interopérabilité, un nom de classe runtime incorrect déclenche une invalidCastException.

Ajouter un projet de projection à la solution de composant

Tout d’abord, avec la solution CppWinRTComponentProjectionSample toujours ouverte dans Visual Studio, supprimez le projet SimpleMathProjection de cette solution. Ensuite, supprimez de votre système de fichiers le dossier SimpleMathProjection (ou renommez-le si vous préférez). Ces étapes sont nécessaires pour que vous puissiez suivre cette procédure pas à pas.

  1. Ajoutez un nouveau projet de bibliothèque C# à votre solution.

    1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur votre nœud de solution, puis cliquez sur Ajouter>un nouveau projet.
    2. Dans la boîte de dialogue Ajouter un nouveau projet, tapez Bibliothèque de classes dans la zone de recherche. Choisissez C# dans la liste de langues, puis choisissez Windows dans la liste de plateformes. Choisissez le modèle de projet C# appelé simplement Bibliothèque de classes (sans préfixe ni suffixes), puis cliquez sur Suivant.
    3. Nommez le nouveau projet SimpleMathProjection. L’emplacement doit déjà être défini sur le même \CsWinRT\src\Samples\NetProjectionSample dossier que celui dans lequel se trouve le dossier SimpleMathComponent , mais confirmez cela. Cliquez ensuite sur Suivant.
    4. Dans la page Informations supplémentaires , sélectionnez .NET 6.0 (prise en charge à long terme), puis choisissez Créer.
  2. Supprimez le fichier stub Class1.cs du projet.

  3. Utilisez les étapes ci-dessous pour installer le package NuGet C#/WinRT.

    1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur votre projet SimpleMathProjection , puis sélectionnez Gérer les packages NuGet.
    2. Dans l’onglet Parcourir , tapez ou collez Microsoft.Windows.CsWinRT dans la zone de recherche, dans les résultats de la recherche, sélectionnez l’élément avec la dernière version, puis cliquez sur Installer pour installer le package dans le projet SimpleMathProjection .
  4. Ajoutez au projet SimpleMathProjection une référence au projet SimpleMathComponent. Dans Explorateur de solutions, cliquez avec le bouton droit sur le nœud Dépendances sous le nœud projet SimpleMathProjection, sélectionnez Ajouter une référence de projet, puis sélectionnez le projet SimpleMathComponent>OK.

N’essayez pas encore de construire le projet. Nous allons le faire dans une étape ultérieure.

Jusqu’à présent, votre Explorateur de solutions doit ressembler à ceci (vos numéros de version seront différents).

Explorateur de solutions affichant les dépendances de projet de projection

Générer des projets hors source

Pour la solution CppWinRTComponentProjectionSample dans l’exemple de projection C#/WinRT (que vous avez téléchargé ou cloné à partir de GitHub et que vous avez ouvert), l’emplacement de sortie de build est configuré avec le fichier Directory.Build.props pour générer hors source. Cela signifie que les fichiers de la sortie de build sont générés en dehors du dossier source. Nous vous recommandons de générer hors source lorsque vous utilisez l’outil C#/WinRT. Cela empêche le compilateur C# de récupérer par inadvertance tous les fichiers *.cs sous le répertoire racine du projet, ce qui peut entraîner des erreurs de type en double (par exemple lors de la compilation pour plusieurs configurations et/ou plateformes).

Même s’il est déjà configuré pour la solution CppWinRTComponentProjectionSample , suivez les étapes ci-dessous pour vous entraîner à effectuer la configuration pour vous-même.

Pour configurer votre solution pour générer hors source :

  1. Lorsque la solution CppWinRTComponentProjectionSample s’ouvre toujours, cliquez avec le bouton droit sur le nœud de la solution, puis sélectionnez Ajouter>un nouvel élément. Sélectionnez l’élément fichier XML et nommez-le directory.Build.props (sans extension de ). Cliquez sur Oui pour remplacer le fichier existant.

  2. Remplacez le contenu de Directory.Build.props par la configuration ci-dessous.

    <Project>
      <PropertyGroup>
        <BuildOutDir>$([MSBuild]::NormalizeDirectory('$(SolutionDir)', '_build', '$(Platform)', '$(Configuration)'))</BuildOutDir>
        <OutDir>$([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'bin'))</OutDir>
        <IntDir>$([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'obj'))</IntDir>
      </PropertyGroup>
    </Project>
    
  3. Enregistrez et fermez le fichier Directory.Build.props .

Modifier le fichier projet pour exécuter C#/WinRT

Avant de pouvoir appeler l’outil pour générer l’assembly cswinrt.exe de projection, vous devez d’abord modifier le fichier projet pour spécifier quelques propriétés de projet.

  1. Dans l’Explorateur de solutions, double-cliquez sur le nœud SimpleMathProjection pour ouvrir le fichier projet dans l’éditeur.

  2. Mettez à jour l’élément TargetFramework pour cibler une version spécifique du Kit de développement logiciel (SDK) Windows. Cela ajoute des dépendances d'assemblage nécessaires pour prendre en charge l'interopérabilité et la projection. Cet exemple cible la version net6.0-windows10.0.19041.0 (également appelée Windows 10, version 2004). Définissez l’élément Platform sur AnyCPU afin que l’assembly de projection résultant puisse être référencé à partir de toute architecture d’application. Pour permettre la référence des applications afin de prendre en charge les versions antérieures du Kit de développement logiciel (SDK) Windows, vous pouvez également définir la propriété TargetPlatformMinimumVersion.

    <PropertyGroup>
      <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
      <!-- Set Platform to AnyCPU to allow consumption of the projection assembly from any architecture. -->
      <Platform>AnyCPU</Platform>
    </PropertyGroup>
    

    Remarque

    Pour cette procédure pas à pas et l’exemple de code associé, la solution est générée pour x64 et release. Notez que le projet SimpleMathProjection est configuré pour compiler pour AnyCPU pour toutes les configurations architecturales de la solution.

  3. Ajoutez un deuxième PropertyGroup élément (immédiatement après le premier) qui définit plusieurs propriétés C#/WinRT.

    <PropertyGroup>
      <CsWinRTIncludes>SimpleMathComponent</CsWinRTIncludes>
      <CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
    </PropertyGroup>
    

    Voici quelques détails sur les paramètres de cet exemple :

    • La propriété CsWinRTIncludes spécifie les espaces de noms à projeter.
    • La CsWinRTGeneratedFilesDir propriété définit le répertoire de sortie dans lequel les fichiers sources de projection sont générés. Cette propriété est définie sur OutDir, définie dans Directory.Build.props de la section ci-dessus.
  4. Enregistrez et fermez le fichier SimpleMathProjection.csproj, puis cliquez sur Recharger les projets si nécessaire.

Créer un package NuGet avec la projection

Pour distribuer l’assembly de projection pour les développeurs d’applications .NET, vous pouvez créer automatiquement un package NuGet lors de la génération de la solution en ajoutant des propriétés de projet supplémentaires. Pour les cibles .NET, le package NuGet doit inclure l’assembly de projection et l’assembly d’implémentation à partir du composant.

  1. Utilisez les étapes ci-dessous pour ajouter un fichier de spécifications NuGet (.nuspec) au projet SimpleMathProjection .

    1. Dans Explorateur de solutions, cliquez avec le bouton droit sur le nœud SimpleMathProjection , choisissez Ajouternouveau dossier, puis nommez le dossier nuget.
    2. Cliquez avec le bouton droit sur le dossier nuget , choisissez Ajouter>un nouvel élément, choisissez fichier XML et nommez-le SimpleMathProjection.nuspec.
  2. Dans l’Explorateur de solutions, double-cliquez sur le nœud SimpleMathProjection pour ouvrir le fichier projet dans l’éditeur. Ajoutez le groupe de propriétés suivant au fichier SimpleMathProjection.csproj ouvert (immédiatement après les deux éléments existants PropertyGroup ) pour générer automatiquement le package. Ces propriétés spécifient le NuspecFile et le répertoire pour générer le package NuGet.

    <PropertyGroup>
      <GeneratedNugetDir>.\nuget\</GeneratedNugetDir>
      <NuspecFile>$(GeneratedNugetDir)SimpleMathProjection.nuspec</NuspecFile>
      <OutputPath>$(GeneratedNugetDir)</OutputPath>
      <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    </PropertyGroup>
    

    Remarque

    Si vous préférez générer un package séparément, vous pouvez également choisir d’exécuter l’outil nuget.exe à partir de la ligne de commande. Pour plus d’informations sur la création d’un package NuGet, consultez Créer un package à l’aide de l’interface CLI nuget.exe.

  3. Ouvrez le fichier SimpleMathProjection.nuspec pour modifier les propriétés de création de package et collez le code suivant. L’extrait de code ci-dessous est un exemple de spécification NuGet pour distribuer SimpleMathComponent à plusieurs frameworks cibles. Notez que l’assembly de projection, SimpleMathProjection.dll, est spécifié au lieu de SimpleMathComponent.winmd pour cible lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll. Ce comportement est nouveau dans .NET 6 et versions ultérieures et est activé par C#/WinRT. L’assembly d’implémentation, , SimpleMathComponent.dlldoit également être distribué et sera chargé au moment de l’exécution.

    <?xml version="1.0" encoding="utf-8"?>
    <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
      <metadata>
        <id>SimpleMathComponent</id>
        <version>0.1.0-prerelease</version>
        <authors>Contoso Math Inc.</authors>
        <description>A simple component with basic math operations</description>
        <dependencies>
          <group targetFramework="net6.0-windows10.0.19041.0" />
          <group targetFramework=".NETCoreApp3.0" />
          <group targetFramework="UAP10.0" />
          <group targetFramework=".NETFramework4.6" />
        </dependencies>
      </metadata>
      <files>
        <!--Support .NET 6, .NET Core 3, UAP, .NET Framework 4.6, C++ -->
        <!--Architecture-neutral assemblies-->
        <file src="..\..\_build\AnyCPU\Release\SimpleMathProjection\bin\SimpleMathProjection.dll" target="lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\netcoreapp3.0\SimpleMathComponent.winmd" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\uap10.0\SimpleMathComponent.winmd" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\net46\SimpleMathComponent.winmd" />
        <!--Architecture-specific implementation DLLs should be copied into RID-relative folders-->
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-x64\native\SimpleMathComponent.dll" />
        <!--To support x86 and Arm64, build SimpleMathComponent for those other architectures and uncomment the entries below.-->
        <!--<file src="..\..\_build\Win32\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-x86\native\SimpleMathComponent.dll" />-->
        <!--<file src="..\..\_build\arm64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-arm64\native\SimpleMathComponent.dll" />-->
      </files>
    </package>
    

    Remarque

    SimpleMathComponent.dll, l’assembly d’implémentation pour le composant, est propre à l’architecture. Si vous prendz en charge d’autres plateformes (par exemple, x86 ou Arm64), vous devez d’abord générer SimpleMathComponent pour les plateformes souhaitées et ajouter ces fichiers d’assembly au dossier RID approprié. L’assembly de projection SimpleMathProjection.dll et le composant SimpleMathComponent.winmd sont tous deux neutres en architecture.

  4. Enregistrez et fermez les fichiers que vous venez de modifier.

Générer la solution pour générer la projection et le package NuGet

Avant de construire la solution, veillez à vérifier les paramètres du Configuration Manager dans Visual Studio, sous Build>Configuration Manager. Pour cette procédure pas à pas, définissez la Configuration sur la Version et la Plateforme sur x64 pour la solution.

À ce stade, vous pouvez maintenant générer la solution. Cliquez avec le bouton droit sur votre nœud de solution, puis sélectionnez Générer la solution. Cela va d’abord générer le projet SimpleMathComponent, puis le projet SimpleMathProjection. Le composant WinMD et l’assembly d’implémentation (SimpleMathComponent.winmd et SimpleMathComponent.dll), les fichiers sources de projection et l’assembly de projection (SimpleMathProjection.dll), seront tous générés sous le répertoire de sortie _build . Vous pourrez également voir le package NuGet généré, SimpleMathComponent0.1.0-prerelease.nupkg, sous le dossier \SimpleMathProjection\nuget .

Important

Si l’un des fichiers mentionnés ci-dessus n’est pas généré, générez la solution une deuxième fois. Vous devrez peut-être également fermer la solution, puis la rouvrir avant de la reconstruire.

Vous devrez peut-être fermer et rouvrir la solution pour qu’elle .nupkg apparaisse dans Visual Studio comme illustré (ou simplement sélectionner, puis désélectionner Afficher tous les fichiers).

Explorateur de solutions montrant la génération de projection

Référencer le package NuGet dans une application console C# .NET 6

Pour utiliser SimpleMathComponent à partir d’un projet .NET, vous pouvez simplement ajouter à un nouveau projet .NET une référence au package NuGet SimpleMathComponent0.1.0-prerelease.nupkg que nous avons créé dans la section précédente. Les étapes suivantes montrent comment procéder en créant une application console simple dans une solution distincte.

  1. Utilisez les étapes ci-dessous pour créer une solution contenant un projet d’application console C# (la création de ce projet dans une nouvelle solution vous permet de restaurer le package NuGet SimpleMathComponent indépendamment ).

    Important

    Nous allons créer ce projet d'application console dans le dossier \CsWinRT\src\Samples\NetProjectionSample, que vous trouverez dans votre copie téléchargée ou clonée de l'exemple de projection C#/WinRT.

    1. Dans une nouvelle instance de Visual Studio, sélectionnez Nouveau>>.
    2. Dans la boîte de dialogue Créer un projet, recherchez le modèle de projet application console. Choisissez le modèle de projet C# appelé simplement Application console (sans préfixe ni suffixes), puis cliquez sur Suivant. Si vous utilisez Visual Studio 2019, le modèle de projet est Application console.
    3. Nommez le nouveau projet SampleConsoleApp, définissez son emplacement dans le même dossier \CsWinRT\src\Samples\NetProjectionSample que les dossiers SimpleMathComponent et SimpleMathProjection, puis cliquez sur Suivant.
    4. Dans la page Informations supplémentaires , sélectionnez .NET 6.0 (prise en charge à long terme), puis choisissez Créer.
  2. Dans l’Explorateur de solutions, double-cliquez sur le nœud SampleConsoleApp pour ouvrir le fichier projet SampleConsoleApp.csproj, puis modifiez les propriétés et TargetFramework les Platform propriétés pour qu’elles apparaissent comme indiqué dans la liste suivante. Ajoutez l’élément Platform s’il n’y est pas.

    <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
      <Platform>x64</Platform>
    </PropertyGroup>
    
  3. Avec le fichier projet SampleConsoleApp.csproj toujours ouvert, nous allons ensuite ajouter au projet SampleConsoleApp une référence au package NuGet SimpleMathComponent . Pour restaurer le SimpleMathComponent NuGet lors de la génération du projet, vous pouvez utiliser la propriété avec le chemin d’accès au dossier NuGet dans la solution de votre composant. Copiez la configuration suivante et collez-la dans SampleConsoleApp.csproj (à l’intérieur de l’élément Project ).

    <PropertyGroup>
      <RestoreSources>
        https://api.nuget.org/v3/index.json;
        ../SimpleMathProjection/nuget
      </RestoreSources>
    </PropertyGroup>
    
    <ItemGroup>
      <PackageReference Include="SimpleMathComponent" Version="0.1.0-prerelease" />
    </ItemGroup>
    

    Important

    Le RestoreSources chemin d’accès du package SimpleMathComponent indiqué ci-dessus est défini sur ../SimpleMathProjection/nuget. Ce chemin d’accès est correct, à condition que vous avez suivi les étapes décrites dans cette procédure pas à pas, afin que les projets SimpleMathComponent et SampleConsoleApp se trouvent tous les deux dans le même dossier (le NetProjectionSample dossier, dans ce cas). Si vous avez fait quelque chose de différent, vous devez ajuster ce chemin en conséquence. Vous pouvez également ajouter un flux de package NuGet local à votre solution.

  4. Modifiez le fichier Program.cs pour utiliser les fonctionnalités fournies par SimpleMathComponent.

    var x = new SimpleMathComponent.SimpleMath();
    Console.WriteLine("Adding 5.5 + 6.5 ...");
    Console.WriteLine(x.add(5.5, 6.5).ToString());
    
  5. Enregistrez et fermez les fichiers que vous venez de modifier, puis générez et exécutez l’application console. Vous devriez voir le résultat ci-dessous.

    sortie de console NET5

Problèmes connus

  • Lors de la génération du projet de projection, une erreur peut s’afficher : Erreur MSB3271 Il y a eu une incompatibilité entre l’architecture du processeur du projet en cours de génération « MSIL » et l’architecture du processeur , « x86 », du fichier d’implémentation .\SimpleMathComponent.dll" for « .. \SimpleMathComponent.winmd". Cette incompatibilité peut entraîner des échecs d’exécution. Envisagez de modifier l’architecture de processeur ciblée de votre projet par le biais de Configuration Manager afin d’aligner les architectures de processeur entre votre projet et votre fichier d’implémentation, ou de choisir un fichier winmd avec un fichier d’implémentation qui a une architecture de processeur qui correspond à l’architecture de processeur ciblée de votre projet. Pour contourner cette erreur, ajoutez la propriété suivante à votre fichier projet de bibliothèque C# :
    <PropertyGroup>
        <!-- Workaround for MSB3271 error on processor architecture mismatch -->
        <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
    </PropertyGroup>
    

Considérations supplémentaires

L’assembly de projection C# (ou d’interopérabilité) que nous avons montré comment créer dans cette rubrique est assez simple : il n’a pas de dépendances sur d’autres composants. Toutefois, pour générer une projection C# pour un composant C++/WinRT qui a des références aux types du Kit de développement logiciel (SDK) d’application Windows, dans le projet de projection, vous devez ajouter une référence au package NuGet du SDK d’application Windows. Si de telles références sont manquantes, vous verrez des erreurs telles que « Type <T> introuvable ».

Une autre chose que nous faisons dans cette rubrique consiste à distribuer la projection en tant que package NuGet. Cette est actuellement nécessaire.

Ressources