Autoria de um componente C# Windows Runtime para utilização a partir de uma aplicação C++/WinRT

Este tópico guia-o pelo processo de adicionar um componente simples em C# ao seu projeto C++/WinRT.

O Visual Studio facilita a criação e implementação dos seus próprios tipos personalizados do Windows Runtime dentro de um projeto de componente do Windows Runtime (WRC) escrito em C# ou Visual Basic, bem como a referenciação desse WRC a partir de um projeto de aplicação em C++ e o consumo desses tipos personalizados nessa aplicação.

Internamente, os seus tipos de Windows Runtime podem usar qualquer funcionalidade .NET permitida numa aplicação UWP.

Note

Para mais informações, consulte a visão geral dos componentes do Windows Runtime com C# e Visual Basic e .NET para aplicações UWP.

Externamente, os membros do seu tipo só podem expor tipos do Windows Runtime como parâmetros e valores de retorno. Quando constrói a sua solução, o Visual Studio constrói o seu projeto .NET WRC e depois executa uma etapa de compilação que cria um ficheiro de metadados do Windows (.winmd). Este é o seu componente Windows Runtime (WRC), que o Visual Studio inclui na sua aplicação.

Note

O .NET mapeia automaticamente alguns tipos .NET comuns, como tipos de dados primitivos e tipos de coleção, para os seus equivalentes no Windows Runtime. Estes tipos .NET podem ser usados na interface pública de um componente do Windows Runtime e aparecerão aos utilizadores do componente como os tipos correspondentes do Windows Runtime. Veja componentes do Windows Runtime com C# e Visual Basic.

Pré-requisitos

Criar uma App em Branco

No Visual Studio, crie um novo projeto usando o modelo de projeto Blank App (C++/WinRT) (para aplicações de desktop WinUI 3, use o modelo Blank App, Packaged (WinUI 3 in Desktop)). Certifica-te de que estás a usar o modelo (C++/WinRT), e não o modelo (Universal Windows).

Defina o nome do novo projeto como CppToCSharpWinRT para que a estrutura das pastas corresponda à do guia passo a passo.

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

No Visual Studio, crie o project component: No Explorador de Soluções, abra o menu de atalhos para a solução CppToCSharpWinRT e escolha Adicionar, e depois selecione New Project para adicionar um novo project C# à solução. Na secção Templates Instalados da caixa de diálogo Adicionar Novo Project, escolhe Visual C#, depois Windows, e depois Universal. Escolha o modelo Windows Runtime Component (Universal Windows) e introduza SampleComponent para o nome do projeto.

Note

Na caixa de diálogo New Plataforma Universal do Windows Project, escolha Windows 10 Creators Update (10.0; Build 15063) como Versão mínima. Por favor, consulte a secção Versão Mínima da Candidatura abaixo para mais informações.

Adicione o método GetMyString em C#

No projeto SampleComponent , mude o nome da classe de Class1 para Example. Depois adiciona 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 defeito, a classe está marcada como publicamente selada. Todas as classes de Windows Runtime que expões do teu componente devem ser seladas.

Note

Opcional: Para ativar o IntelliSense para os membros recentemente adicionados, no Explorador de Soluções, abra o menu de atalhos para o projeto SampleComponent e depois escolha Build.

Consulte o C# SampleComponent do projeto CppToCSharpWinRT

No Explorador de Soluções, no projeto C++/WinRT, abre o menu de atalho para Referências e depois escolhe Adicionar Referência para abrir o diálogo Adicionar Referência. Escolha Projetos e depois escolha Solução. Seleciona a caixa de seleção para o projeto SampleComponent e escolhe OK para adicionar uma referência.

Note

Opcional: Para ativar o IntelliSense para o projeto C++/WinRT, no Explorador de Soluções, abra o menu de atalhos para o projeto CppToCSharpWinRT e depois escolha Compilar.

Editar MainPage.h

Abre MainPage.h no projeto CppToCSharpWinRT e depois adiciona dois itens. Primeiro, adicione #include "winrt/SampleComponent.h" no final das instruções #include e, depois, um campo winrt::SampleComponent::Example à struct MainPage.

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

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

Note

No 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 criar e executar o projeto. Cada vez que clicas no botão, o número no botão aumenta.

Chamada do Windows em C++/WinRT para uma captura de ecrã de um componente C#

Tip

No Visual Studio, crie o projeto componente: No Explorador de Soluções, abra o menu de atalhos para o projeto CppToCSharpWinRT e escolha Propriedades, e depois escolha Depuração em Propriedades de Configuração. Defina o Tipo Depurador para Gerido e Nativo se quiser depurar tanto o código C# (gerido) como o C++ (nativo). Propriedades de Depuração em C++

Versão Mínima da Aplicação

O Mínimo de Aplicação da versão do projeto C# controlará a versão do .NET usada para compilar a aplicação. Por exemplo, escolher o Windows 10 Fall Creators Update (10.0; Build 16299) ou posterior permitirá o .NET Standard 2.0 e o suporte para processadores Windows Arm64.

Tip

Recomendamos o uso de versões Mínimas de Aplicação inferiores a 16299 para evitar configurações adicionais de compilação caso não seja necessário suporte para .NET Standard 2.0 ou Arm64.

Configurar para a Windows 10 Fall Creators Update (10.0; Compilação 16299)

Siga estes passos para ativar o suporte ao .NET Standard 2.0 ou Windows Arm64 nos projetos C# referenciados do seu projeto C++/WinRT.

No Visual Studio, vai ao Explorador de Soluções e abre o menu de atalhos para o projeto CppToCSharpWinRT. Escolha Propriedades e defina a versão Universal Aplicação do Windows Min para Windows 10 Fall Creators Update (10.0; Build 16299) (ou superior). Faz o mesmo com o projeto SampleComponent .

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

Copie e cole o seguinte XML 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 para DotNetNativeVersion, DotNetNativeSharedLibrary, e UWPCoreRuntimeSdkVersion podem variar consoante a versão do Visual Studio. Para defini-los com os valores corretos, abra o %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages e consulte o subdiretório correspondente a 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 do .NET nativo que começa por 2.2. No exemplo abaixo, é 2.2.12-rel-31116-00.

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

Existem várias arquiteturas suportadas para a 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.

De seguida, imediatamente após o primeiro PropertyGroup, adicione o seguinte (inalterado).

  <!-- 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 ficheiro do projeto, imediatamente antes da etiqueta de fecho Project, adicione o seguinte (inalterado).

  <!-- 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 ficheiro do projeto no Visual Studio. Para isso, no Visual Studio Explorador de Soluções, abra o menu de atalhos para a project CppToCSharpWinRT e escolha Recarregar Project.

Construção para .NET Native

Recomenda-se construir e testar a sua aplicação com o componente C# construído contra .NET nativo. No Visual Studio, abra o menu de atalhos para o project CppToCSharpWinRT e escolha Descarregar Project para abrir CppToCSharpWinRT.vcxproj no editor de texto.

De seguida, defina a UseDotNetNativeToolchain propriedade para true nas configurações Release e Arm64 no ficheiro do projeto C++.

No Explorador de Soluções do Visual Studio, abra o menu de atalho para o projeto CppToCSharpWinRT e escolha Recarregar Projeto.

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

Referenciar outros pacotes NuGet de C#

Se o componente C# estiver a referenciar outros pacotes nuget, o ficheiro de projeto da aplicação pode precisar de dependências de ficheiros de lista do pacote nuget como conteúdo de implementação. Por exemplo, se o componente C# referenciar o pacote NuGet Newtonsoft.Json, o mesmo pacote NuGet e a mesma dependência de ficheiro também devem ser referenciados no projeto da aplicação.

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

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

No projeto CppToCSharpWinRT , localiza o ficheiro packages.config e adiciona a referência nuget apropriada. Isto vai instalar o pacote Nuget na pasta do pacote da solução.

Em packages.config, adicione a mesma referência do pacote Nuget:

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

Depois, adicione o seguinte ao ficheiro de projeto da aplicação para referenciar a dependência de ficheiro apropriada a partir da pasta de pacotes da solução. Por exemplo, em CppToCSharpWinRT.vcxproj adicionar 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>