Criando um componente C# do Windows Runtime para uso em um aplicativo C++/WinRT

Este tópico explica o processo de adição de um componente C# simples ao seu projeto C++/WinRT.

O Visual Studio facilita criar e implantar seus próprios tipos personalizados do Windows Runtime dentro de um projeto de componente do Windows Runtime (WRC) escrito em C# ou Visual Basic e, em seguida, referenciar esse WRC em um projeto de aplicativo C++ e consumir esses tipos personalizados nesse aplicativo.

Internamente, seus tipos de Windows Runtime podem usar qualquer funcionalidade .NET permitida em um aplicativo UWP.

Externamente, os membros do seu tipo podem expor somente tipos do Windows Runtime para seus parâmetros e valores retornados. Quando você cria sua solução, Visual Studio cria seu projeto wrc .NET e executa uma etapa de build que cria um arquivo de metadados Windows (.winmd). Este é o seu componente do Windows Runtime (WRC), que o Visual Studio inclui no seu aplicativo.

Note

.NET mapeia automaticamente alguns tipos de .NET comumente usados, como tipos de dados primitivos e tipos de coleta, para seus equivalentes de Windows Runtime. Esses tipos de .NET podem ser usados na interface pública de um componente Windows Runtime e serão exibidos aos usuários do componente como os tipos de Windows Runtime correspondentes. Consulte Componentes do Windows Runtime com C# e Visual Basic.

Pré-requisitos

Criar um aplicativo em branco

Em Visual Studio, crie um novo projeto usando o modelo de projeto Aplicativo em Branco (C++/WinRT) (para aplicativos da área de trabalho WinUI 3, use o modelo Aplicativo em Branco, Empacotado (WinUI 3 na área de trabalho)). Verifique se você está usando o modelo (C++/WinRT) e não o modelo (Universal Windows).

Defina o nome do novo projeto como CppToCSharpWinRT para que sua estrutura de pastas corresponda ao passo a passo.

Adicionar um componente de Windows Runtime C# à solução

No Visual Studio, crie o projeto do componente: no Gerenciador de Soluções, abra o menu de atalho da solução CppToCSharpWinRT e escolha Add e, em seguida, New Project para adicionar um novo projeto C# à solução. Na seção Modelos Instalados da caixa de diálogo Adicionar Novo Project, escolha Visual C#e escolha Windows e, em seguida, Universal. Escolha o modelo Windows Runtime Component (Universal Windows) e insira SampleComponent para o nome do projeto.

Note

Na caixa de diálogo Novo Projeto da Plataforma Universal do Windows, escolha Windows 10 Creators Update (10.0; Build 15063) como versão mínima. Consulte a seção Versão Mínima do Aplicativo abaixo para obter mais informações.

Adicionar o método GetMyString em C#

No projeto SampleComponent , altere o nome da classe de Classe1 para Exemplo. Em seguida, adicione dois membros simples à classe, um campo privado int e um método de instância chamado GetMyString:

    public sealed class Example
    {
        int MyNumber;

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

Note

Por padrão, a classe é declarada como public sealed. Todas as classes do Windows Runtime que você expõe no seu componente devem ser seladas.

Note

Opcional: para habilitar o IntelliSense para os membros recém-adicionados, em Gerenciador de Soluções, abra o menu de atalho do projeto SampleComponent e escolha Compilar.

Referenciar o SampleComponent em C# do projeto CppToCSharpWinRT

Em Gerenciador de Soluções, no projeto C++/WinRT, abra o menu de atalho para Referências e escolha Adicionar Referência para abrir a caixa de diálogo Adicionar Referência. Escolha Projetos e escolha solução. Marque a caixa de seleção do projeto SampleComponent e escolha OK para adicionar uma referência.

Note

Opcional: para habilitar o IntelliSense para o projeto C++/WinRT, em Gerenciador de Soluções, abra o menu de atalho para o projeto CppToCSharpWinRT e escolha Compilar.

Editar MainPage.h

Abra MainPage.h no projeto CppToCSharpWinRT e adicione dois itens. Primeiro, adicione #include "winrt/SampleComponent.h" ao final das declarações #include e, em seguida, um campo winrt::SampleComponent::Example à estrutura MainPage.

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

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

Note

Em Visual Studio, MainPage.h está listado em MainPage.xaml.

Editar MainPage.cpp

Em MainPage.cpp, altere a implementação de Mainpage::ClickHandler para chamar o método C# GetMyString.

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

    hstring myString = myExample.GetMyString();

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

Executar o projeto

Agora você pode compilar e executar o projeto. Cada vez que você clicar no botão, o número no botão será incrementado.

Captura de tela do Windows C++/WinRT chamando um componente em C#

Tip

Em Visual Studio, crie o projeto de componente: em Gerenciador de Soluções, abra o menu de atalho do projeto CppToCSharpWinRT e escolha Propriedades e escolha Depuração em Propriedades de Configuração. Defina o Tipo de Depurador como Gerenciado e Nativo se desejar depurar o código C# (gerenciado) e C++ (nativo). Propriedades de depuração do C++

Versão mínima do aplicativo

O Application Minimum da versão do projeto C# controlará a versão de .NET usada para compilar o aplicativo. Por exemplo, escolher Windows 10 Fall Creators Update (10.0; Build 16299) ou posterior habilitará o suporte ao .NET Standard 2.0 e ao processador Windows Arm64.

Tip

Recomendamos usar versões de Mínimo do Aplicativo inferiores a 16299 para evitar configuração de compilação adicional se o suporte ao .NET Standard 2.0 ou ao Arm64 não for necessário.

Configurar para Windows 10 Fall Creators Update (10.0; Build 16299)

Siga estas etapas para habilitar o suporte .NET Standard 2.0 ou Windows Arm64 nos projetos em C# referenciados do seu projeto C++/WinRT.

Em Visual Studio, vá para o Gerenciador de Soluções e abra o menu de atalho do projeto CppToCSharpWinRT. Escolha Propriedades e defina a versão Universal aplicativo do Windows Min para Windows 10 Fall Creators Update (10.0; Build 16299) (ou superior). Faça o mesmo para o projeto SampleComponent .

Em Visual Studio, abra o menu de atalho do project CppToCSharpWinRT e escolha Descarregar Project para abrir CppToCSharpWinRT.vcxproj no editor de texto.

Copie e cole o XML a seguir para o primeiro PropertyGroup em 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 -->

Os valores de DotNetNativeVersion, DotNetNativeSharedLibrarye UWPCoreRuntimeSdkVersion podem variar dependendo da versão de Visual Studio. Para defini-los com os valores corretos, abra %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages e examine o subdiretório para cada valor na tabela abaixo. O %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler diretório terá um subdiretório que contém uma versão instalada de .NET nativo que começa com 2.2. No exemplo abaixo, é 2.2.12-rel-31116-00.

Variável MSBuild Diretório 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

Há várias arquiteturas com suporte para Microsoft. Net.Native.SharedLibrary. Substitua x64 pela arquitetura apropriada. Por exemplo, a arm64 arquitetura estaria no %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64.microsoft.net.native.sharedlibrary diretório.

Em seguida, imediatamente após o primeiro PropertyGroup, adicione o seguinte (sem alterações).

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

No final do arquivo do projeto, pouco antes da tag de fechamento Project, adicione o seguinte (sem alterações).

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

Recarregue o arquivo de projeto em Visual Studio. Para fazer isso, no Visual Studio Gerenciador de Soluções, abra o menu de atalho do project CppToCSharpWinRT e escolha Recarregar Project.

Compilar para .NET Native

É recomendável criar e testar seu aplicativo com o componente C# criado em .NET nativo. Em Visual Studio, abra o menu de atalho do project CppToCSharpWinRT e escolha Descarregar Project para abrir CppToCSharpWinRT.vcxproj no editor de texto.

Em seguida, defina a propriedade UseDotNetNativeToolchain como true nas configurações Release e Arm64 no arquivo de projeto de C++.

No Visual Studio Gerenciador de Soluções, abra o menu de atalho do project CppToCSharpWinRT e escolha Recarregar Project.

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

Referência a outros pacotes NuGet do C#

Se o componente C# estiver fazendo referência a outros pacotes nuget, o arquivo de projeto do aplicativo poderá precisar listar dependências de arquivo do pacote nuget como conteúdo de implantação. Por exemplo, se o componente C# fizer referência ao pacote nuget Newtonsoft.Json, o mesmo pacote nuget e a dependência de arquivo também deverão ser referenciados no projeto do aplicativo.

No arquivo SampleComponent.csproj , adicione a referência do pacote nuget:

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

No projeto CppToCSharpWinRT , localize o arquivo packages.config e adicione a referência de nuget apropriada. Isso instalará o pacote nuget na pasta do pacote da solução.

Em packages.config, adicione a mesma referência de pacote nuget:

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

Em seguida, adicione o seguinte ao arquivo de projeto do aplicativo para referenciar a dependência de arquivo apropriada na pasta de pacotes da solução. Por exemplo, em CppToCSharpWinRT.vcxproj adicione o seguinte:

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