Compartilhar via


Como portar um projeto C++/CLI para o .NET

A partir do Visual Studio 2019, projetos C++/CLI podem ser direcionados ao .NET. Esse suporte possibilita a portabilidade de aplicativos da área de trabalho do Windows com camadas de interoperabilidade C++/CLI do .NET Framework para o .NET. Este artigo descreve como portar projetos C++/CLI do .NET Framework para o .NET.

Limitações do C++/CLI no .NET Core

Há algumas limitações importantes com projetos C++/CLI e .NET em comparação com o .NET Framework:

  • Não há suporte para compilar um projeto C++/CLI em um executável. Você deve compilar para uma DLL.
  • O suporte do C++/CLI para .NET é somente do Windows.
  • Projetos C++/CLI não podem ser direcionados ao .NET Standard.
  • Os projetos C++/CLI não dão suporte ao formato de arquivo de projeto no estilo SDK mais recente. Em vez disso, os projetos C++/CLI usam o mesmo formato de arquivo .vcxproj que outros projetos do Visual Studio C++ usam.
  • Projetos C++/CLI não podem direcionar várias plataformas .NET. Se você precisar criar um projeto C++/CLI para .NET e .NET Framework, use arquivos de projeto separados.
  • O .NET não dá suporte às compilações -clr:pure ou -clr:safe, apenas à opção -clr:netcore mais recente (que é equivalente ao -clr no .NET Framework).

Portar um projeto C++/CLI

Para portar um projeto C++/CLI para .NET, faça as seguintes alterações no arquivo .vcxproj . Essas etapas de migração diferem das etapas necessárias para outros tipos de projeto porque projetos C++/CLI não usam arquivos de projeto no estilo SDK.

  1. Substitua as propriedades em <CLRSupport>true</CLRSupport> por <CLRSupport>NetCore</CLRSupport>. Essa propriedade geralmente está em grupos de propriedades específicos à configuração, portanto, talvez seja necessário substituí-la em vários lugares.
  2. Substitua as propriedades em <TargetFrameworkVersion> por <TargetFramework>net8.0</TargetFramework>. Certifique-se de alterar o tag e o valor.
  3. Remova as referências do .NET Framework para System, System.Data, System.Windows.Forms e System.Xml, como <Reference Include="System" />. Os assemblies do SDK do .NET são referenciados automaticamente ao usar <CLRSupport>NetCore</CLRSupport>.
  4. Atualize o uso da API em arquivos .cpp , conforme necessário, para remover APIs indisponíveis para .NET. Como projetos C++/CLI tendem a ser camadas de interoperabilidade bastante finas, muitas vezes não há muitas alterações necessárias. Você pode usar o Analisador de Portabilidade do .NET para identificar APIs .NET sem suporte usadas por binários C++/CLI.
  5. Se o projeto for um executável, execute as seguintes etapas:
    1. Altere o tipo de projeto para uma biblioteca.
    2. Crie um novo projeto executável do .NET.
    3. No projeto executável do .NET, adicione uma referência à biblioteca .NET do C++/CLI.

Uso do WPF e do Windows Forms

Os projetos do .NET C++/CLI podem usar os Windows Forms e as APIs do WPF. Para usar essas APIs da área de trabalho do Windows, você precisa adicionar referências de estrutura explícitas às bibliotecas de interface do usuário. Projetos no estilo SDK que usam APIs da área de trabalho do Windows fazem referência às bibliotecas de estrutura necessárias automaticamente usando o Microsoft.NET.Sdk.WindowsDesktop SDK. Como os projetos C++/CLI não usam o formato de projeto no estilo SDK, eles precisam adicionar referências de estrutura explícitas ao direcionar o .NET Core.

Para usar AS APIs do Windows Forms, adicione essa referência ao arquivo .vcxproj :

<!-- Reference all of Windows Forms -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />

Para usar APIs do WPF, adicione esta referência ao arquivo .vcxproj :

<!-- Reference all of WPF -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WPF" />

Para usar as APIs do Windows Forms e do WPF, adicione essa referência ao arquivo .vcxproj :

<!-- Reference the entirety of the Windows desktop framework:
     Windows Forms, WPF, and the types that provide integration between them -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App" />

Atualmente, não é possível adicionar essas referências usando o gerenciador de referência do Visual Studio. Em vez disso, atualize o arquivo de projeto editando-o manualmente. No Visual Studio, você precisa descarregar o projeto primeiro. Você também pode usar outro editor, como o Visual Studio Code.

Construir sem o MSBuild

Também é possível criar projetos C++/CLI sem usar o MSBuild. Siga estas etapas para criar um projeto C++/CLI para .NET Core diretamente com cl.exe e link.exe:

  1. Ao compilar, passe -clr:netcore para cl.exe.

  2. Referencie os assemblies de referência do .NET necessários.

  3. Ao vincular, forneça o diretório de host do aplicativo .NET como um LibPath, para que ijwhost.lib possa ser encontrado.

  4. Copie ijwhost.dll do diretório de host do aplicativo .NET para o diretório de saída do projeto.

  5. Verifique se existe um arquivo runtimeconfig.json para o primeiro componente do aplicativo que executa o código gerenciado. Para versões mais recentes do Visual Studio, um arquivo runtime.config é criado e copiado automaticamente.

    Para versões mais antigas do Visual Studio, se o aplicativo tiver um ponto de entrada nativo, você precisará criar manualmente o seguinte arquivo runtimeconfig.json para a primeira biblioteca C++/CLI a usar o runtime do .NET. Se uma biblioteca C++/CLI for chamada de um ponto de entrada gerenciado, a biblioteca não precisará de um arquivo runtimeconfig.json , pois o assembly do ponto de entrada tem um que é usado ao iniciar o runtime.

    {
       "runtimeOptions": {
          "tfm": "net8.0",
          "framework": {
          "name": "Microsoft.NETCore.App",
          "version": "8.0.0"
          }
       }
    }
    

Observação

Os conjuntos C++/CLI destinados ao .NET 7 ou a uma versão posterior são continuamente carregados no compartimento padrão AssemblyLoadContext. No entanto, no .NET 6 e em versões anteriores, os assemblies do C++/CLI podem ser carregados várias vezes, cada vez em um novo AssemblyLoadContext. Se a primeira vez que o código gerenciado em um assembly do C++/CLI for executado:

  • Vier de um chamador nativo, o assembly será carregado em um AssemblyLoadContext separado.
  • Vier de um chamador gerenciado, o assembly será carregado no mesmo AssemblyLoadContext que o chamador, geralmente o padrão.

Para sempre carregar o assembly do C++/CLI no padrão AssemblyLoadContext, é possível adicionar uma chamada de estilo "inicializar" do assembly do ponto de entrada no assembly do C++/CLI. Para obter mais informações, confira este problema de dotnet/runtime.