Compartilhar via


Como migrar para /clr

Este artigo discute problemas que surgem ao compilar código nativo com /clro . (Para obter mais informações, consulte /clr (Compilação do Common Language Runtime).) /clr permite que o código C++ nativo invoque e seja invocado 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

O 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::FromName. No entanto, se um tipo estiver em uma DLL MSIL (compilada com /clr), a chamada para FromName poderá 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á-la e invocá-la 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 ao 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 do compilador relacionados à conformidade aprimorada do Standard C++ no Visual Studio.

Os projetos criados com versões anteriores do Visual Studio também devem ser compilados primeiro sem /clr. O Visual Studio agora aumentou a conformidade com o Standard C++ e algumas alterações significativas. As alterações que provavelmente exigirão mais atenção são os recursos de segurança no CRT. O código que usa o CRT provavelmente produzirá avisos de substituição. Esses avisos podem ser suprimidos, mas é preferível migrar para as novas versões aprimoradas de segurança das funções CRT, pois elas 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, /Tp, /TC, /TP (Especificar tipo de arquivo de origem).) Embora os arquivos de código-fonte C++ sejam necessários para /clro , não é necessário refatorar seu código para usar paradigmas orientados a objetos.

É 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 alteração 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

Reconfigurar as configurações do projeto

Depois que o projeto for compilado e executado no Visual Studio, você deverá criar novas configurações de projeto em /clr 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 selecionado na caixa de diálogo das páginas de propriedades, as configurações do projeto não compatíveis são /clr desativadas. (As opções desativadas não serã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 intactas as configurações originais do projeto.

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 /clr compilação pode ser criada a partir de uma cópia do original.

Alterar as 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 um projeto de serviço Web do Visual Studio 2003, a opção do /Zl compilador é adicionada à página de propriedades da Linha de Comando . Isso causa erros LNK2001. Remova /Zl da página de propriedades da Linha de Comando para resolver os erros. Para obter mais informações, consulte /Zl (Omitir nome da biblioteca padrão) e Definir propriedades do compilador e do build.

Para projetos criados com makefiles, as opções do compilador incompatíveis devem ser desabilitadas manualmente depois de /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

Cabeçalhos pré-compilados são suportados em /clr. No entanto, se você compilar apenas alguns de seus arquivos CPP com /clr (compilando o restante como nativo), algumas alterações serão necessárias. Os cabeçalhos pré-compilados gerados com /clr não são compatíveis com os cabeçalhos pré-compilados gerados sem /clr, porque /clr o 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 C/C++ e selecione Cabeçalhos Pré-compilados. Em seguida, altere a propriedade Criar/Usar Cabeçalhos Pré-compilados para "Não Usando Cabeçalhos Pré-compilados".)

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 não/clr para usar cabeçalhos pré-compilados separados. Você pode configurá-los em uma etapa: Selecione vários módulos para compilar /clr usando o Gerenciador de Soluções. Clique com o botão direito do mouse no grupo e selecione Propriedades. Em seguida, altere as propriedades Criar/Usar PCH Através do Arquivo e Arquivo de Cabeçalho Pré-compilado para usar um nome de arquivo de cabeçalho e um arquivo PCH diferentes, respectivamente.

Correção de erros

Compilar seu código pode /clr resultar em erros de compilador, vinculador ou runtime. 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. (Ocorrem erros 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 em que o tipo foi definido. Você pode achar útil girar a ordem em que os arquivos OBJ são enviados ao vinculador, para descobrir o local da outra versão do tipo de dados.

Bloqueio de 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 de DLL é propensa a erros e não é recomendada no /clr código. Isso ocorre 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 há suporte 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 o 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 os métodos nativos do C++ 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 do nativo para o MSIL, você notará um aumento no tamanho do seu conjunto de trabalho. Esse aumento ocorre porque o Common Language Runtime fornece muitos recursos para garantir que os programas sejam executados corretamente. Se o /clr aplicativo não estiver sendo executado corretamente, talvez você queira habilitar o Aviso do Compilador desativado por padrão (nível 1 e 3) C4793.

O programa trava no desligamento

Em alguns casos, o CLR pode ser desligado antes que o código gerenciado termine de ser executado. O 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 for compilado, vinculado e executado, você poderá 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)