Creazione di un componente Windows Runtime C# per l'uso da un'app C++/WinRT

Questo argomento illustra il processo di aggiunta di un semplice componente C# al progetto C++/WinRT.

Visual Studio semplifica la creazione e la distribuzione di tipi di Windows Runtime personalizzati all'interno di un progetto di componente Windows Runtime (WRC) scritto con C# o Visual Basic, quindi fare riferimento a tale WRC da un progetto di applicazione C++ e usare tali tipi personalizzati da tale applicazione.

Internamente, i tipi di Windows Runtime possono usare qualsiasi funzionalità .NET consentita in un'applicazione UWP.

All'esterno, i membri del tipo possono esporre solo tipi di Windows Runtime per i relativi parametri e valori di ritorno. Quando si compila la soluzione, Visual Studio compila il progetto WRC .NET e quindi esegue un passaggio di compilazione che crea un file di metadati Windows (con estensione winmd). Questo è il componente Windows Runtime (WRC), che Visual Studio include nella tua app.

Note

.NET esegue automaticamente il mapping di alcuni tipi di .NET comunemente usati, ad esempio tipi di dati primitivi e tipi di raccolta, ai relativi equivalenti Windows Runtime. Questi tipi di .NET possono essere usati nell'interfaccia pubblica di un componente Windows Runtime e vengono visualizzati agli utenti del componente come tipi di Windows Runtime corrispondenti. Vedere componenti di Windows Runtime con C# e Visual Basic.

Prerequisiti

Creare un'app vuota

In Visual Studio, creare un nuovo progetto usando il modello di progetto App vuota (C++/WinRT) (per le app desktop WinUI 3, usare il modello App vuota, con pacchetto (WinUI 3 per desktop)). Assicurarsi di usare il modello (C++/WinRT) e non quello (Universal Windows).

Impostare il nome del nuovo progetto su CppToCSharpWinRT in modo che la struttura di cartelle corrisponda alla procedura dettagliata.

Aggiungere un componente Windows Runtime C# alla soluzione

In Visual Studio creare il componente project: in Esplora soluzioni aprire il menu di scelta rapida per la soluzione CppToCSharpWinRT e quindi scegliere Aggiungi, quindi scegliere Nuovo Project per aggiungere un nuovo project C# alla soluzione. Nella sezione Modelli installati della finestra di dialogo Aggiungi nuovo Project scegliere Visual C#, quindi scegliere Windows e quindi Universale. Scegliere il modello Windows Runtime Componente (Windows universale) e immettere SampleComponent come nome del progetto.

Note

Nella finestra di dialogo Nuovo piattaforma UWP (Universal Windows Platform) Project scegliere Windows 10 Creators Update (10.0; Build 15063) come versione minima. Per altre informazioni, vedere la sezione Versione minima applicazione di seguito.

Aggiungere il metodo C# GetMyString

Nel progetto SampleComponent modificare il nome della classe da Class1 a Example. Aggiungere quindi due membri semplici alla classe, un campo privato int e un metodo di istanza denominato GetMyString:

    public sealed class Example
    {
        int MyNumber;

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

Note

Per impostazione predefinita, la classe è dichiarata public sealed. Tutte le classi Windows Runtime che il componente espone devono essere sealed.

Note

Facoltativo: per abilitare IntelliSense per i membri appena aggiunti, in Esplora soluzioni aprire il menu di scelta rapida per il progetto SampleComponent e quindi scegliere Compila.

Fare riferimento al C# SampleComponent dal progetto CppToCSharpWinRT

In Esplora soluzioni, nel progetto C++/WinRT aprire il menu di scelta rapida per Riferimenti e quindi scegliere Aggiungi riferimento per aprire la finestra di dialogo Aggiungi riferimento. Scegliere Progetti e quindi scegliere Soluzione. Selezionare la casella di controllo per il progetto SampleComponent e scegliere OK per aggiungere un riferimento.

Note

Facoltativo: per abilitare IntelliSense per il progetto C++/WinRT, in Esplora soluzioni aprire il menu di scelta rapida per il progetto CppToCSharpWinRT e quindi scegliere Compila.

Modificare MainPage.h

Aprire MainPage.h nel progetto CppToCSharpWinRT e quindi aggiungere due elementi. Per prima cosa, aggiungi #include "winrt/SampleComponent.h" alla fine delle istruzioni #include, quindi un campo winrt::SampleComponent::Example alla struttura MainPage.

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

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

Note

In Visual Studio è MainPage.h elencato in MainPage.xaml.

Modifica MainPage.cpp

In MainPage.cpp, modificare l'implementazione Mainpage::ClickHandler per chiamare il metodo C# GetMyString.

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

    hstring myString = myExample.GetMyString();

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

Eseguire il progetto

A questo punto puoi compilare ed eseguire il progetto. Ogni volta che si fa clic sul pulsante, il numero nel pulsante verrà incrementato.

Screenshot di Windows C++/WinRT che chiama un componente C#

Suggerimento

In Visual Studio creare il progetto componente: in Esplora soluzioni aprire il menu di scelta rapida per il progetto CppToCSharpWinRT e scegliere Proprietà, quindi scegliere Debug in Proprietà di configurazione. Impostare Il tipo di debugger su Gestito e Nativo se si vuole eseguire il debug del codice C# (gestito) e C++ (nativo). Proprietà di debug C++

Versione minima dell'applicazione

La versione minima dell'applicazione del progetto C# controlla la versione di .NET usata per compilare l'applicazione. Ad esempio, scegliendo Windows 10 Fall Creators Update (10.0; Build 16299) o versioni successive abiliterà .NET standard 2.0 e Windows supporto del processore Arm64.

Suggerimento

È consigliabile usare le versioni minime dell'applicazione inferiori a 16299 per evitare una configurazione di compilazione aggiuntiva se non è necessario .NET supporto Standard 2.0 o Arm64.

Configurare per Windows 10 Fall Creators Update (10.0; Build 16299)

Seguire questi passaggi per abilitare .NET Standard 2.0 o il supporto per Windows Arm64 nei progetti C# a cui fa riferimento il progetto C++/WinRT.

In Visual Studio passare al Esplora soluzioni e aprire il menu di scelta rapida per il progetto CppToCSharpWinRT. Scegliere Proprietà e impostare la versione Universale app di Windows Min su Windows 10 Fall Creators Update (10.0; Build 16299) (o versione successiva). Eseguire la stessa operazione per il progetto SampleComponent .

In Visual Studio, apri il menu di scelta rapida per il progetto CppToCSharpWinRT e scegli Scarica progetto per aprire CppToCSharpWinRT.vcxproj nell'editor di testo.

Copiare e incollare il codice XML seguente nel primo PropertyGroup in 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 -->

I valori per DotNetNativeVersion, DotNetNativeSharedLibrarye UWPCoreRuntimeSdkVersion possono variare a seconda della versione di Visual Studio. Per impostarli sui valori corretti, aprire %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages e controllare la sottodirectory relativa a ciascun valore nella tabella seguente. La %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler directory avrà una sottodirectory che contiene una versione installata di .NET nativa che inizia con 2.2. Nell'esempio seguente è 2.2.12-rel-31116-00.

Variabile 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

Sono disponibili più architetture supportate per Microsoft. Net.Native.SharedLibrary. Sostituire x64 con l'architettura appropriata. Ad esempio, l'architettura arm64 si trova nella %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64.microsoft.net.native.sharedlibrary directory .

Successivamente, subito dopo il primo PropertyGroup, aggiungere quanto segue (non modificato).

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

Alla fine del file project, subito prima del tag di chiusuraProject, aggiungere quanto segue (non modificato).

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

Ricaricare il file di progetto in Visual Studio. A tale scopo, nel Visual Studio Esplora soluzioni aprire il menu di scelta rapida per il project CppToCSharpWinRT e scegliere Ricarica Project.

Compilazione per .NET nativa

È consigliabile compilare e testare l'applicazione con il componente C# compilato con .NET nativo. In Visual Studio, aprire il menu di scelta rapida per il progetto CppToCSharpWinRT e scegliere Scarica progetto per aprire CppToCSharpWinRT.vcxproj nell'editor di testo.

Impostare quindi la UseDotNetNativeToolchain proprietà su true nelle configurazioni Release e Arm64 nel file di progetto C++.

Nel Visual Studio Esplora soluzioni aprire il menu di scelta rapida per il project CppToCSharpWinRT e scegliere Ricarica Project.

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

Riferimento ad altri pacchetti NuGet C#

Se il componente C# fa riferimento ad altri pacchetti nuget, il file di progetto dell'applicazione potrebbe richiedere dipendenze di file di elenco dal pacchetto nuget come contenuto della distribuzione. Ad esempio, se il componente C# fa riferimento al pacchetto nuget Newtonsoft.Json, è necessario fare riferimento anche allo stesso pacchetto NuGet e alla stessa dipendenza di file nel progetto dell'applicazione.

Nel file SampleComponent.csproj aggiungere il riferimento al pacchetto nuget:

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

Nel progetto CppToCSharpWinRT individuare il file packages.config e aggiungere il riferimento nuget appropriato. Verrà installato il pacchetto nuget nella cartella del pacchetto della soluzione.

In packages.configaggiungere lo stesso riferimento al pacchetto NuGet:

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

Aggiungere quindi quanto segue al file di progetto dell'applicazione per fare riferimento alla dipendenza del file appropriata dalla cartella del pacchetto della soluzione. Ad esempio, in CppToCSharpWinRT.vcxproj aggiungere quanto segue:

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