Como: Migrar para /clr

Este artigo discute problemas que surgem ao compilar código nativo com /clro . (Para obter mais informações, consulte /clr (Common Language Runtime Compilation).) /clr permite que o código C++ nativo invoque e seja invocado a partir de assemblies .NET, além de outro código C++ nativo. Para obter mais informações sobre as vantagens de compilar com /clro , consulte Assemblies mistos (nativos e gerenciados) e Interoperabilidade nativa e .NET.

Problemas conhecidos ao compilar projetos de biblioteca com /clr

Visual Studio contém alguns problemas conhecidos ao compilar projetos de biblioteca com /clr:

  • Seu código pode consultar tipos em tempo de execução com CRuntimeClass::FromNameo . No entanto, se um tipo estiver em uma DLL MSIL (compilada com /clr), a chamada para FromName pode falhar se ocorrer antes que os construtores estáticos sejam executados na DLL gerenciada. (Você não verá esse problema se a chamada ocorrer depois que o FromName código for executado na DLL gerenciada.) Para contornar esse problema, você pode forçar a construção do construtor estático gerenciado: definir uma função na DLL gerenciada, exportá-lo e invocá-lo do aplicativo MFC nativo. Por exemplo:

    // MFC extension DLL Header file:
    __declspec( dllexport ) void EnsureManagedInitialization () {
       // managed code that won't be optimized away
       System::GC::KeepAlive(System::Int32::MaxValue);
    }
    

Compilar com o Visual C++

Antes de usar /clr em qualquer módulo em seu projeto, primeiro compile e vincule seu projeto nativo com o Visual Studio.

As etapas a seguir, seguidas em ordem, fornecem o caminho mais fácil para uma /clr compilação. É importante compilar e executar seu projeto após cada uma dessas etapas.

Atualizando de versões anteriores do Visual Studio

Se você estiver atualizando o Visual Studio de uma versão anterior, poderá ver erros de compilador relacionados à conformidade aprimorada do Standard C++ no Visual Studio.

Projetos criados com versões anteriores do Visual Studio também devem primeiro ser compilados sem /clr. O Visual Studio agora aumentou a conformidade com o C++ padrão e algumas alterações de quebra. As alterações que provavelmente exigirão mais atenção são os Recursos de Segurança na CRT. O código que usa a CRT provavelmente produzirá avisos de depreciação. Esses avisos podem ser suprimidos, mas a migração para as novas versões aprimoradas de segurança das funções CRT é preferível, pois fornecem melhor segurança e podem revelar problemas de segurança em seu código.

Atualizando de extensões gerenciadas para C++

No Visual Studio 2005 e versões posteriores, o código escrito com extensões gerenciadas para C++ não será compilado em /clr.

Converter código C para C++

Embora o Visual Studio compile arquivos C, é necessário convertê-los em C++ para uma /clr compilação. O nome do arquivo real não precisa ser alterado; você pode usar /Tp (consulte /Tc, , /TC/Tp, /TP (Especificar tipo de arquivo de origem).) Embora os arquivos de código-fonte C++ sejam necessários para o , não é necessário refatorar seu código para /clrusar paradigmas orientados a objeto.

É provável que o código C exija alterações quando compilado como um arquivo C++. As regras de segurança de tipo C++ são rígidas, portanto, as conversões de tipo devem ser explicitadas com conversões. Por exemplo, malloc retorna um ponteiro void, mas pode ser atribuído a um ponteiro para qualquer tipo em C com uma conversão:

int* a = malloc(sizeof(int));   // C code
int* b = (int*)malloc(sizeof(int));   // C++ equivalent

Os ponteiros de função também são estritamente type-safe no C++, portanto, o código C a seguir exige modificação. Em C++, é melhor criar um que defina o tipo de typedef ponteiro de função e, em seguida, usar esse tipo para converter ponteiros de função:

NewFunc1 = GetProcAddress( hLib, "Func1" );   // C code
typedef int(*MYPROC)(int);   // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );

O C++ também exige que as funções sejam protótipos ou totalmente definidas antes de serem referenciadas ou invocadas.

Identificadores usados no código C que são palavras-chave em C++ (comovirtual, new, delete, bool, true, false etc). devem ser renomeados. Essa mudança geralmente pode ser feita com operações simples de pesquisa e substituição.

COMObj1->lpVtbl->Method(COMObj, args);  // C code
COMObj2->Method(args);  // C++ equivalent

Redefinir configurações do projeto

Depois que seu projeto compila e é executado no Visual Studio, você deve criar novas configurações de projeto para /clr em vez de modificar as configurações padrão. /clr é incompatível com algumas opções do compilador. A criação de configurações separadas permite que você crie seu projeto como nativo ou gerenciado. Quando /clr selecionada na caixa de diálogo de páginas de propriedades, as configurações do projeto não compatíveis com /clr são desabilitadas. (As opções desativadas não são restauradas automaticamente se /clr forem desmarcadas posteriormente.)

Criar novas configurações de projeto

Você pode usar a opção Copiar Configurações da opção na Caixa de diálogo Nova Configuração do Projeto (Build>Configuration Manager>Active Solution Configuration>New) para criar uma configuração de projeto com base nas configurações de projeto existentes. Crie uma cópia da configuração uma vez para a configuração de depuração e uma vez para a configuração de versão. As alterações subsequentes podem ser aplicadas somente às /clrconfigurações -específicas, deixando as configurações originais do projeto intactas.

Projetos que usam regras de build personalizadas podem exigir atenção extra.

Essa etapa tem implicações diferentes para projetos que usam makefiles. Nesse caso, um destino de compilação separado pode ser configurado ou uma versão específica para compilação pode ser criada a /clr partir de uma cópia do original.

Alterar configurações do projeto

/clrpode ser selecionado no ambiente de desenvolvimento seguindo as instruções em /clr (Common Language Runtime Compilation). Conforme mencionado anteriormente, essa etapa desabilitará automaticamente as configurações conflitantes do projeto.

Observação

Ao atualizar uma biblioteca gerenciada ou projeto de serviço Web do Visual Studio 2003, a /Zl opção do compilador é adicionada à página de propriedades Linha de comando. Isso causa erros LNK2001. Remova /Zl da página de propriedades Linha de Comando para resolver os erros. Para obter mais informações, consulte /Zl (Omitir o nome da biblioteca padrão) e Definir propriedades do compilador e da compilação.

Para projetos criados com makefiles, as opções de compilador incompatíveis devem ser desativadas manualmente uma vez /clr adicionadas. Para obter informações sobre as opções do compilador que não são compatíveis com /clro , consulte /clr restrições.

Cabeçalhos pré-compilados

Os cabeçalhos pré-compilados são suportados em /clr. No entanto, se você compilar apenas alguns de seus arquivos CPP com /clr (compilando o resto como nativo), algumas alterações serão necessárias. Os cabeçalhos pré-compilados gerados com não são compatíveis com /clr cabeçalhos pré-compilados gerados sem /clr, porque /clr gera e requer metadados. Os módulos compilados com /clr não podem usar cabeçalhos pré-compilados que não incluem metadados e os não-módulos não podem usar arquivos de cabeçalho pré-compilados/clr que contêm metadados.

A maneira mais fácil de compilar um projeto com o qual /clr alguns módulos são compilados é desabilitar totalmente os cabeçalhos pré-compilados. (Na caixa de diálogo Páginas de propriedades do projeto, abra o Nó C/C++ e selecione Cabeçalhos pré-compilados. Em seguida, altere a propriedade Create/Use Precompiled Headers para "Not Using Precompiled Headers ".)

No entanto, particularmente para projetos grandes, os cabeçalhos pré-compilados fornecem uma velocidade de compilação muito melhor, portanto, desabilitar esse recurso não é desejável. Nesse caso, é melhor configurar os /clr arquivos e non-para usar cabeçalhos pré-compilados/clr separados. Você pode configurá-los em uma etapa: Selecionar vários módulos com /clr os quais compilar usando o Gerenciador de Soluções. Clique com o botão direito do mouse no grupo e selecione Propriedades. Em seguida, altere as propriedades Create/Use PCH Through File e Precompiled Header File para usar um nome de arquivo de cabeçalho e um arquivo PCH diferentes, respectivamente.

Correção de erros

Compilar seu código com /clr pode resultar em erros de compilador, vinculador ou tempo de execução. Esta seção discute os problemas mais comuns.

Mesclagem de metadados

Versões diferentes de tipos de dados podem fazer com que o vinculador falhe porque os metadados gerados para os dois tipos não correspondem. (Os erros ocorrem quando você define condicionalmente membros de um tipo, mas as condições não são as mesmas para todos os arquivos CPP que usam o tipo.) Nesse caso, o vinculador falha, relatando apenas o nome do símbolo e o nome do segundo arquivo OBJ onde o tipo foi definido. Você pode achar que é útil girar a ordem em que os arquivos OBJ são enviados para o vinculador, para descobrir o local da outra versão do tipo de dados.

Bloqueio do carregador

O "deadlock de bloqueio do carregador" pode ocorrer, mas é determinístico e detectado e relatado no runtime. Consulte Inicialização de Assemblies Mistos para obter informações detalhadas, diretrizes e soluções.

Exportações de dados

A exportação de dados DLL é propensa a erros e não é recomendada no /clr código. É porque a inicialização da seção de dados de uma DLL não é garantida até que alguma parte gerenciada da DLL seja executada. Metadados de referência com #using diretivas.

Visibilidade de tipo

Os tipos nativos são private por padrão. Um private tipo nativo não é visível fora da DLL. Resolva esse erro adicionando public a esses tipos.

Problemas de ponto flutuante e alinhamento

__controlfp não é suportado no Common Language Runtime. (Para obter mais informações, consulte _control87, _controlfp, __control87_2.) O CLR também não respeita align.

Inicialização COM

O Common Language Runtime inicializa o COM automaticamente quando um módulo é inicializado (quando o COM é inicializado automaticamente, ele é feito como MTA). Como resultado, a inicialização explícita do COM gera códigos de retorno que indicam que o COM já está inicializado. A tentativa de inicializar explicitamente o COM com um modelo de threading quando o CLR já tiver inicializado o COM para outro modelo de threading pode fazer com que o aplicativo falhe.

O Common Language Runtime inicia COM como MTA por padrão; use /CLRTHREADATTRIBUTE (Definir atributo de thread CLR) para modificar o modelo COM.

Problemas de desempenho

Você pode ver um desempenho reduzido quando métodos C++ nativos gerados para MSIL são chamados indiretamente (por meio de chamadas de função virtual ou usando ponteiros de função). Para saber mais, consulte Double Thunking.

Ao passar de nativo para MSIL, você notará um aumento no tamanho do seu conjunto de trabalho. Esse aumento acontece porque o Common Language Runtime fornece muitos recursos para garantir que os programas sejam executados corretamente. Se o aplicativo não estiver sendo executado corretamente, convém habilitar o /clr Aviso do Compilador (nível 1 e 3) C4793 fora do padrão.

O programa falha no desligamento

Em alguns casos, o CLR pode ser desligado antes que o código gerenciado termine de ser executado. Uso de std::set_terminate e SIGTERM pode causar o desligamento. Para obter mais informações, consulte signal constantes e set_terminate.

Usando novos recursos do Visual C++

Depois que seu aplicativo compila, vincula e executa, você pode começar a usar os recursos do .NET em qualquer módulo compilado com /clro . Para obter mais informações, consulte Extensões de componentes para plataformas de runtime.

Para obter mais informações sobre programação .NET no Visual C++, consulte:

Confira também

Assemblies mistos (nativos e gerenciados)