Ler em inglês

Compartilhar via


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

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

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

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

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

Portar um projeto do C++/CLI

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

  1. Substitua as propriedades <CLRSupport>true</CLRSupport> por <CLRSupport>NetCore</CLRSupport>. Essa propriedade geralmente está em grupos de propriedades específicos da configuração. Portanto, você pode ter que substituí-la em vários lugares.
  2. Substitua as propriedades <TargetFrameworkVersion> por <TargetFramework>net8.0</TargetFramework>. Altere a 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 nos arquivos .cpp, conforme necessário, para remover as APIs indisponíveis para o .NET. Como os projetos do C++/CLI tendem a ter camadas de interoperabilidade bastante finas, geralmente não há muitas alterações necessárias. Você pode usar o Analisador de Portabilidade do .NET para identificar as APIs do .NET sem suporte usadas por binários do C++/CLI.
  5. Se o seu projeto era executável, execute as seguintes etapas:
    1. Altere o tipo de projeto para uma biblioteca.
    2. Crie um novo projeto executável .NET.
    3. No projeto executável .NET, adicione referência à biblioteca .NET C++/CLI.

Uso do WPF e do Windows Forms

Os projetos do C++/CLI do .NET podem usar as APIs do Windows Forms e 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. Os projetos no estilo SDK que usam as 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 do C++/CLI não usam o formato de projeto no estilo SDK, eles precisam adicionar referências de estrutura explícitas quando direcionados para o .NET Core.

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

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

Para usar as 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 esta 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" />

No momento, não é possível adicionar essas referências usando o gerenciador de referências do Visual Studio. Em vez disso, atualize o arquivo de projeto por meio de edição manual. No Visual Studio, primeiro será necessário descarregar o projeto. Você também pode usar outro editor, como o Visual Studio Code.

Compilar sem o MSBuild

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

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

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

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

  4. Copie o ijwhost.dll do diretório de host do aplicativo do .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. Um arquivo runtime.config é criado e copiado automaticamente, em versões mais recentes do Visual Studio.

    Em versões mais antigas do Visual Studio, se o aplicativo tiver um ponto de entrada nativo, será necessário criar manualmente o seguinte arquivo runtimeconfig.json para a primeira biblioteca do C++/CLI que usar o runtime do .NET. Se uma biblioteca do 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 já tem um arquivo que é usado ao iniciar o runtime.

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

Observação

Os assemblies do C++/CLI direcionados para o .NET 7 ou para uma versão posterior são sempre carregados no 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.