Compartilhar via


An Overview of Managed/Unmanaged Code Interoperability (Uma visão geral da interoperabilidade de código gerenciado/não gerenciado)

 

Sonja Keserovic, Gerente de Programa
David Mortenson, engenheiro líder de design de software
Adam Nathan, engenheiro líder de design de software em teste

Microsoft Corporation

Outubro de 2003

Aplica-se a:
   Microsoft® .NET Framework
   Interoperabilidade COM

Resumo: Este artigo fornece fatos básicos sobre a interoperabilidade entre código gerenciado e não gerenciado e diretrizes e práticas comuns para acessar e encapsular a API não gerenciada do código gerenciado e para expor APIs gerenciadas a chamadores não gerenciados. Considerações de segurança e confiabilidade, dados de desempenho e práticas gerais para processos de desenvolvimento também são realçados. (14 páginas impressas)

Pré-requisitos: O público-alvo deste documento inclui desenvolvedores e gerentes que precisam tomar decisões de alto nível sobre onde usar o código gerenciado. Para fazer isso, é útil entender como funciona a interação entre código gerenciado e não gerenciado e como as diretrizes atuais se aplicam a cenários específicos.

Sumário

Introdução à interoperabilidade
Diretrizes de interoperabilidade
Segurança
Confiabilidade
Desempenho
Apêndice 1: Cruzando o limite de interoperabilidade
Apêndice 2: Recursos
Apêndice 3: Glossário de Termos

Introdução à interoperabilidade

O CLR (Common Language Runtime) promove a interação do código gerenciado com componentes COM, serviços COM+, a API Win32® e outros tipos de código não gerenciado. Tipos de dados, mecanismos de tratamento de erros, regras de criação e destruição e diretrizes de design variam entre modelos de objeto gerenciados e não gerenciados. Para simplificar a interoperação entre o código gerenciado e não gerenciado e facilitar o caminho de migração, a camada de interoperabilidade clr oculta as diferenças entre esses modelos de objeto de clientes e servidores.

A interoperabilidade ("interoperabilidade") é bidirecional, o que possibilita:

  • Chamar APIs não gerenciadas do código gerenciado

    Isso pode ser feito para APIs simples (exportações de DLL estáticas, como a API win32, que é exposta de DLLs como kernel32.dll e user32.dll) e APIs COM (modelos de objeto, como aqueles expostos pelo Microsoft® Word, Excel, Internet Explorer, ActiveX® Data Objects (ADO) e assim por diante).

  • Expor APIs gerenciadas a código não gerenciado

    Exemplos de como fazer isso incluem a criação de um suplemento para um aplicativo baseado em COM, como o Windows Media® Player, ou a inserção de um controle de Windows Forms gerenciado em um formulário MFC.

Três tecnologias complementares permitem essas interações gerenciadas/não gerenciadas:

  • A Invocação de Plataforma (às vezes chamada de P/Invoke) permite chamar qualquer função em qualquer linguagem não gerenciada, desde que sua assinatura seja redeclarada no código-fonte gerenciado. Isso é semelhante à funcionalidade fornecida pela instrução Declare no Visual Basic® 6.0.
  • A interoperabilidade COM permite chamar componentes COM em qualquer linguagem gerenciada de maneira semelhante ao uso de componentes gerenciados normais e vice-versa. A interoperabilidade COM é composta pelos principais serviços fornecidos pelo CLR, além de algumas ferramentas e APIs no namespace System.Runtime.InteropServices .
  • A interoperabilidade do C++ (às vezes chamada de IJW (It Just Works)) é um recurso específico do C++, que permite que APIs simples e APIs COM sejam usadas diretamente, pois sempre foram usadas. Isso é mais poderoso do que a interoperabilidade COM, mas requer muito mais cuidado. Verifique se você marcar os recursos do C++ antes de usar essa tecnologia.

Diretrizes de interoperabilidade

Chamando APIs não gerenciadas do Código Gerenciado

Há vários tipos de APIs não gerenciadas e vários tipos de tecnologias de interoperabilidade disponíveis para chamá-las. Sugestões sobre como e quando usar essas tecnologias são descritas nesta seção. Observe que essas sugestões são muito gerais e não abrangem todos os cenários. Você deve avaliar seus cenários com cuidado e aplicar práticas de desenvolvimento e/ou soluções que façam sentido para seu cenário.

Chamando APIs Simples Não Gerenciadas

Há dois mecanismos para chamar APIs simples não gerenciadas do código gerenciado: por meio da Invocação de Plataforma (disponível em todas as linguagens gerenciadas) ou por meio da interoperabilidade do C++ (disponível no C++).

Antes de decidir chamar uma API simples usando qualquer uma dessas tecnologias de interoperabilidade, você deve determinar se há funcionalidade equivalente disponível no .NET Framework. É recomendável que, sempre que possível, você use .NET Framework funcionalidade em vez de chamar APIs não gerenciadas.

Para chamar apenas alguns métodos não gerenciados ou para chamar APIs simples simples simples, a sugestão é usar a invocação de plataforma em vez de interoperabilidade do C++. Escrever declarações de invocação de plataforma para APIs simples simples simples é simples. O CLR cuidará do carregamento de DLL e de todo o marshaling de parâmetros. Até mesmo o trabalho de escrever algumas declarações de invocação de plataforma para APIs simples complexas é insignificante em comparação com o custo de usar a interoperabilidade do C++ e introduzir um novo módulo inteiro escrito em C++.

Para encapsular APIs simples não gerenciadas complexas ou para encapsular APIs planas não gerenciadas que estão sendo alteradas enquanto o código gerenciado está em desenvolvimento, a sugestão é usar a interoperabilidade do C++ em vez da invocação de plataforma. A camada C++ pode ser muito fina e o restante do código gerenciado pode ser escrito em qualquer outra linguagem gerenciada de sua escolha. Usar a invocação de plataforma nesses cenários exigiria muito esforço para declarar novamente partes complexas da API no código gerenciado e mantê-las em sincronia com as APIs não gerenciadas. O uso da interoperabilidade do C++ resolve esse problema permitindo o acesso direto a APIs não gerenciadas, o que não requer reescrita, apenas a inclusão de um arquivo de cabeçalho.

Chamando APIs COM

Há duas maneiras de chamar componentes COM do código gerenciado: por meio da interoperabilidade COM (disponível em todas as linguagens gerenciadas) ou por meio da interoperabilidade C++ (disponível em C++).

Para chamar componentes COM compatíveis com a Automação OLE, a sugestão é usar a interoperabilidade COM. O CLR cuidará da ativação do componente COM e do marshaling de parâmetros.

Para chamar componentes COM com base na IDL (Interface Definition Language), a sugestão é usar a interoperabilidade C++. A camada C++ pode ser muito fina e o restante do código gerenciado pode ser escrito em qualquer linguagem gerenciada. A interoperabilidade COM depende de informações de bibliotecas de tipos para fazer chamadas de interoperabilidade corretas, mas as bibliotecas de tipos normalmente não contêm todas as informações presentes em arquivos IDL. O uso da interoperabilidade do C++ resolve esse problema permitindo o acesso direto a essas APIs COM.

Para empresas que possuem APIs COM que já foram enviadas, é importante considerar o envio de PIAs (assemblies de interoperabilidade primários) para essas APIs, facilitando o consumo para clientes gerenciados.

Árvore de decisão para chamar APIs não gerenciadas

Figura 1. Chamando árvore de decisão de APIs não gerenciadas

Expondo APIs gerenciadas a código não gerenciado

Há duas main maneiras de expor uma API gerenciada a chamadores puramente não gerenciados: como uma API COM ou como uma API simples. Para clientes não gerenciados do C++ que estão dispostos a recompilar seu código com o Visual Studio® .NET, há uma terceira opção: acessar diretamente a funcionalidade gerenciada por meio da interoperabilidade do C++. As sugestões de como e quando usar essas opções são descritas nesta seção.

Acessando diretamente uma API gerenciada

Se um cliente não gerenciado for escrito em C++, ele poderá ser compilado com o compilador do .NET C++ do Visual Studio como uma "imagem de modo misto". Depois que isso for feito, o cliente não gerenciado poderá acessar diretamente qualquer API gerenciada. No entanto, algumas regras de codificação se aplicam ao acesso a objetos gerenciados de código não gerenciado; marcar a documentação do C++ para obter mais detalhes.

O acesso direto é a opção preferencial, pois não requer nenhuma consideração especial dos desenvolvedores de API gerenciada. Eles podem projetar sua API gerenciada de acordo com as diretrizes de design de API gerenciadas (DG) e ter certeza de que a API ainda estará acessível a chamadores não gerenciados.

Expondo uma API Gerenciada como uma API COM

Cada classe gerenciada pública pode ser exposta a clientes não gerenciados por meio da interoperabilidade COM. Esse processo é muito fácil de implementar, pois a camada de interoperabilidade COM cuida de todo o encanamento COM. Assim, por exemplo, cada classe gerenciada parece implementar IUnknown, IDispatch, ISupportErrorInfo e algumas outras interfaces COM padrão.

Apesar de expor APIs gerenciadas como APIs COM é fácil, os modelos de objeto COM e gerenciados são muito diferentes. Portanto, expor a API gerenciada ao COM sempre deve ser uma decisão de design explícita. Alguns recursos disponíveis no mundo gerenciado não têm equivalente no mundo COM e não poderão ser utilizáveis de clientes COM. Por isso, geralmente há tensão entre as DGs (diretrizes de design de API) gerenciadas e a compatibilidade com COM.

Se os clientes COM forem importantes, escreva sua API gerenciada de acordo com as diretrizes de design da API gerenciada e, em seguida, escreva um wrapper gerenciado fino amigável ao COM em torno de sua API gerenciada que será exposta ao COM.

Expondo uma API Gerenciada como uma API Simples

Às vezes, clientes não gerenciados não podem usar COM. Por exemplo, eles podem já estar escritos para usar APIs simples e não podem ser alterados ou recompilados. O C++ é a única linguagem de alto nível que permite expor APIs gerenciadas como APIs simples. Fazer isso não é tão simples quanto expor uma API gerenciada como uma API COM. É uma técnica muito avançada que requer conhecimento avançado da interoperabilidade do C++ e as diferenças entre os mundos gerenciados e não gerenciados.

Exponha sua API gerenciada como uma API simples somente se absolutamente necessário. Se você não tiver escolha, certifique-se de marcar a documentação do C++ e esteja totalmente ciente de todas as limitações.

Árvore de decisão para expor APIs gerenciadas

Figura 2. Expondo a árvore de decisão de APIs Gerenciadas

Segurança

O Common Language Runtime é fornecido com um sistema de segurança, o CAS ( Code Access Security ), que regula o acesso a recursos protegidos com base em informações sobre a origem de um assembly. Chamar código não gerenciado apresenta um grande risco de segurança. Sem as verificações de segurança apropriadas, o código não gerenciado pode manipular qualquer estado de qualquer aplicativo gerenciado no processo CLR. Também é possível chamar recursos em código não gerenciado diretamente, sem que esses recursos estejam sujeitos a verificações de permissão cas. Por esse motivo, qualquer transição para código não gerenciado é considerada uma operação altamente protegida e deve incluir uma marcar de segurança. Essa marcar de segurança procura a permissão de código não gerenciada que exige que o assembly que contém a transição de código não gerenciado, bem como todos os assemblies que a chamam, tenham o direito de realmente invocar código não gerenciado.

Há alguns cenários de interoperabilidade limitados em que as verificações de segurança completas são desnecessárias e limitariam indevidamente o desempenho ou o escopo do componente. Esse é o caso se um recurso exposto de código não gerenciado não tiver relevância de segurança (tempo do sistema, coordenadas de janela e assim por diante) ou o recurso só for usado internamente no assembly e não for exposto publicamente a chamadores arbitrários. Nesses casos, você pode suprimir a marcar de segurança completa para permissão de código não gerenciado em relação a todos os chamadores das APIs relevantes. Faça isso aplicando o atributo personalizado SuppressUnmanagedCodeSecurity ao respectivo método ou classe de interoperabilidade. Observe que isso pressupõe uma revisão de segurança cuidadosa em que você determinou que nenhum código parcialmente confiável poderia explorar essas APIs.

Confiabilidade

O código gerenciado foi projetado para ser mais confiável e robusto do que o código não gerenciado. Um exemplo de um recurso CLR que promove essas qualidades é a coleta de lixo, que cuida da liberação de memória não utilizado para evitar vazamentos de memória. Outro exemplo é a segurança de tipo gerenciado, que é usada para evitar erros de estouro de buffer e outros erros relacionados a tipos.

Quando você usa qualquer tipo de tecnologia de interoperabilidade, seu código pode não ser tão confiável ou robusto quanto o código gerenciado puro. Por exemplo, talvez seja necessário alocar memória não gerenciada manualmente e lembrar-se de liberá-la quando terminar de usá-la.

Escrever qualquer código de interoperabilidade não trivial requer a mesma atenção à confiabilidade e robustez que escrever código não gerenciado. Mesmo quando todo o código de interoperabilidade for escrito corretamente, seu sistema será tão confiável quanto suas partes não gerenciadas.

Desempenho

A cada transição do código gerenciado para o código não gerenciado (e vice-versa), há alguma sobrecarga de desempenho. A quantidade de sobrecarga depende dos tipos de parâmetros usados. A camada de interoperabilidade CLR usa três níveis de otimização de chamada de interoperabilidade com base no tipo de transição e nos tipos de parâmetro: inlining JIT (just-in-time), stubs de assembly compilados e stubs de marshaling interpretados (em ordem do tipo de chamada mais rápido para o mais lento).

Sobrecarga aproximada para uma chamada de invocação de plataforma: 10 instruções de computador (em um processador x86)

Sobrecarga aproximada para uma chamada de interoperabilidade COM: 50 instruções de computador (em um processador x86)

O trabalho feito por estas instruções é mostrado nas seções do apêndice Chamando uma API Simples: Passo a Passo e Chamando uma API COM: Passo a Passo. Além de garantir que o coletor de lixo não bloqueará threads não gerenciados durante a chamada e lidará com convenções de chamada e exceções não gerenciadas, a interoperabilidade COM faz um trabalho extra para converter a chamada no RCW (runtime Callable Wrapper) em um ponteiro de interface COM apropriado para o contexto atual.

Cada chamada de interoperabilidade apresenta alguma sobrecarga. Dependendo da frequência com que essas chamadas ocorrem e da significância do trabalho que ocorre dentro da implementação do método, a sobrecarga por chamada pode variar de insignificante a muito perceptível.

Com base nessas considerações, a lista a seguir fornece algumas sugestões gerais de desempenho que você pode achar úteis:

  • Se você controlar a interface entre código gerenciado e não gerenciado, torne-a "volumosa" em vez de "tagarela", para reduzir o número total de transições feitas.

    Interfaces tagarelas são interfaces que fazem muitas transições sem executar nenhum trabalho significativo no outro lado do limite de interoperabilidade. Por exemplo, setters de propriedade e getters são tagarelas. Interfaces volumosas são interfaces que fazem apenas algumas transições e a quantidade de trabalho feito no outro lado do limite é significativa. Por exemplo, um método que abre uma conexão de banco de dados e recupera alguns dados é volumoso. Interfaces volumosas envolvem menos transições de interoperabilidade, portanto, você elimina alguma sobrecarga de desempenho.

  • Evite conversões Unicode/ANSI, se possível.

    Converter cadeias de caracteres de Unicode em ANSI e vice-versa é uma operação cara. Por exemplo, se as cadeias de caracteres precisarem ser passadas, mas seu conteúdo não for importante, você poderá declarar um parâmetro de cadeia de caracteres como um IntPtr e o marshaler de interoperabilidade não fará nenhuma conversão.

  • Para cenários de alto desempenho, declarar parâmetros e campos como IntPtr pode aumentar o desempenho, embora às custas da facilidade de uso e da facilidade de manutenção.

    Às vezes, é mais rápido realizar marshaling manual usando métodos disponíveis na classe Marshal , em vez de depender do marshaling de interoperabilidade padrão. Por exemplo, se grandes matrizes de cadeias de caracteres precisarem ser passadas por um limite de interoperabilidade, mas apenas alguns elementos serão necessários, declarar a matriz como um IntPtr e acessar apenas esses poucos elementos manualmente será muito mais rápido.

  • Use InAttribute e OutAttribute sabiamente para reduzir o marshaling desnecessário.

    O marshaler de interoperabilidade usa regras padrão ao decidir se um determinado parâmetro precisa ser realizado em marshaling antes da chamada e realizado marshaling após a chamada. Essas regras são baseadas no nível de indireção e no tipo de parâmetro. Algumas dessas operações podem não ser necessárias dependendo da semântica do método.

  • Use SetLastError=false em assinaturas de invocação de plataforma somente se você chamar Marshal.GetLastWin32Error posteriormente.

    Definir SetLastError=true em assinaturas de invocação de plataforma requer trabalho adicional da camada de interoperabilidade para preservar o último código de erro. Use esse recurso somente quando você depender dessas informações e as usará depois de fazer a chamada.

  • Se e somente se as chamadas não gerenciadas forem expostas de maneira não explorável, use SuppressUnmanagedCodeSecurityAttribute para reduzir o número de verificações de segurança.

    As verificações de segurança são muito importantes. Se sua API não expor recursos protegidos ou informações confidenciais, ou se estiverem bem protegidos, verificações de segurança abrangentes poderão introduzir sobrecarga desnecessária. No entanto, o custo de não fazer nenhuma marcar de segurança é muito alto.

Apêndice 1: Cruzando o limite de interoperabilidade

Chamando uma API Simples: passo a passo

Figura 3. Chamando uma API Simples

  1. Obtenha LoadLibrary e GetProcAddress.
  2. Crie um stub DllImport com base na assinatura que contém o endereço de destino.
  3. Efetuar push de registros salvos por callee.
  4. Configure um quadro DllImport e envie-o por push para a pilha de quadros.
  5. Se a memória temporária for alocada, inicialize uma lista de limpo para liberação rápida quando a chamada for concluída.
  6. Realizar marshaling de parâmetros. (Isso pode alocar memória.)
  7. Altere o modo de Coleta de Lixo de cooperativo para preemptivo, para que uma Coleta de Lixo possa ocorrer a qualquer momento.
  8. Carregue o endereço de destino e chame-o.
  9. Se o bit SetLastError estiver definido, chame GetLastError e armazene o resultado em uma abstração de thread armazenada no Armazenamento Local do Thread.
  10. Altere de volta para o modo de Coleta de Lixo cooperativa.
  11. Se PreserveSig=false e o método retornar uma falha HRESULT, gere uma exceção.
  12. Se nenhuma exceção tiver sido lançada, propagar novamente e parâmetros by-ref .
  13. Restaure o Ponteiro de Pilha Estendida para seu valor original para levar em conta os argumentos exibidos pelo chamador.

Chamando uma API COM: passo a passo

Figura 4. Chamando uma API COM

  1. Crie um stub gerenciado para não gerenciado a partir da assinatura.
  2. Efetuar push de registros salvos por callee.
  3. Configure um quadro de interoperabilidade COM gerenciado para não gerenciado e envie-o por push para a pilha de quadros.
  4. Reserve espaço para dados temporários usados durante a transição.
  5. Se a memória temporária for alocada, inicialize uma lista de limpo para liberação rápida quando a chamada for concluída.
  6. Limpar sinalizadores de exceção de ponto flutuante (somente x86).
  7. Realizar marshaling de parâmetros. (Isso pode alocar memória.)
  8. Recupere o ponteiro de interface correto para o contexto atual dentro do Wrapper Callable do Runtime. Se o ponteiro armazenado em cache não puder ser usado, chame QueryInterface no componente COM para obtê-lo.
  9. Altere o modo de Coleta de Lixo de cooperativo para preemptivo, para que uma Coleta de Lixo possa ocorrer a qualquer momento.
  10. No ponteiro vtable, indexe pelo número do slot, obtenha o endereço de destino e chame-o.
  11. Chame Release no ponteiro da interface se QueryInterface tiver sido chamado anteriormente.
  12. Altere de volta para o modo de Coleta de Lixo cooperativa.
  13. Se a assinatura não estiver marcada como PreserveSig, marcar para a falha HRESULT e gerará uma exceção (potencialmente preenchida com informações de IErrorInfo).
  14. Se nenhuma exceção tiver sido lançada, propagar novamente e parâmetros by-ref .
  15. Restaure o Ponteiro de Pilha Estendida para o valor original para levar em conta os argumentos exibidos pelo chamador.

Chamando uma API gerenciada do COM: passo a passo

Figura 5. Chamar uma API Gerenciada do COM

  1. Crie um stub não gerenciado para gerenciado a partir da assinatura.
  2. Efetuar push de registros salvos por callee.
  3. Configure um quadro de interoperabilidade COM não gerenciado e envie-o por push para a pilha de quadros.
  4. Reserve espaço para dados temporários usados durante a transição.
  5. Altere o modo de Coleta de Lixo de cooperativo para preemptivo para que uma Coleta de Lixo possa ocorrer a qualquer momento.
  6. Recupere o CCW (wrapper callable) COM do ponteiro da interface.
  7. Recupere o objeto gerenciado dentro do CCW.
  8. Faça a transição de appdomains, se necessário.
  9. Se um appdomain estiver sem confiança total, execute quaisquer demandas de link que o método possa ter em relação ao appdomain de destino.
  10. Se a memória temporária for alocada, inicialize uma lista de limpo para liberação rápida quando a chamada for concluída.
  11. Parâmetros de marshal. (Isso pode alocar memória.)
  12. Localize o método gerenciado por destino a ser chamado. (Isso envolve o mapeamento de chamadas de interface para a implementação de destino.)
  13. Armazene em cache o valor retornado. (Se for um valor retornado de ponto flutuante, obtenha-o do registro de ponto flutuante.)
  14. Altere de volta para o modo de Coleta de Lixo cooperativa.
  15. Se uma exceção tiver sido gerada, extraia seu HRESULT para retornar e chame SetErrorInfo.
  16. Se nenhuma exceção tiver sido gerada, propagar novamente os parâmetros e por ref .
  17. Restaure o Ponteiro de Pilha Estendido para o valor original para levar em conta os argumentos gerados pelo chamador.

Apêndice 2: Recursos

Precisa ler!.NET e COM: o guia de interoperabilidade completo de Adam Nathan

Interoperando com código não gerenciado, Guia do Desenvolvedor do Microsoft .NET Framework

Exemplos de interoperabilidade, Microsoft .NET Framework

Blog de Adam Nathan

Blog de Chris Brumme

Apêndice 3: Glossário de Termos

AppDomain (Domínio do Aplicativo) Um domínio de aplicativo pode ser considerado semelhante a um processo leve do sistema operacional e é gerenciado pelo Common Language Runtime.
CCW (wrapper callable COM) Um tipo especial de wrapper criado pela camada de interoperabilidade CLR em torno de objetos gerenciados ativados do código COM. Um CCW oculta as diferenças entre os modelos de objeto COM e gerenciados fornecendo marshaling de dados, gerenciamento de tempo de vida, gerenciamento de identidade, tratamento de erros, transições corretas de apartment e threading e assim por diante. As CCWs expõem a funcionalidade de objeto gerenciado de maneira amigável sem exigir que o implementador de código gerenciado saiba nada sobre o encanamento COM.
CLR O Common Language Runtime.
interoperabilidade COM O serviço fornecido pela camada de interoperabilidade CLR para usar APIs COM do código gerenciado ou expor APIs gerenciadas como APIs COM a clientes não gerenciados. A interoperabilidade COM está disponível em todos os idiomas gerenciados.
Interoperabilidade do C++ O serviço fornecido pelo compilador de linguagem C++ e pelo CLR é usado para misturar diretamente o código gerenciado e não gerenciado no mesmo arquivo executável. A interoperabilidade do C++ geralmente envolve incluir arquivos de cabeçalho em APIs não gerenciadas e seguir determinadas regras de codificação.
API simples complexa APIs que têm assinaturas difíceis de declarar no idioma gerenciado. Por exemplo, métodos com parâmetros de estrutura de tamanho variável são difíceis de declarar, pois não há nenhum conceito equivalente no sistema de tipos gerenciados.
Interoperabilidade O termo geral que aborda qualquer tipo de interoperabilidade entre código gerenciado e não gerenciado (também chamado de "nativo"). A interoperabilidade é um dos muitos serviços fornecidos pelo CLR.
Assembly de interoperabilidade Um tipo especial de assembly gerenciado que contém equivalentes de tipo gerenciado para tipos COM contidos em uma biblioteca de tipos. Normalmente produzido executando a ferramenta Importador de Biblioteca de Tipos (Tlbimp.exe) em uma biblioteca de tipos.
Código gerenciado O código em execução sob o controle do CLR é chamado de código gerenciado. Por exemplo, qualquer código escrito em C# ou Visual Basic .NET é um código gerenciado.
Invocação de plataforma O serviço fornecido pela camada de interoperabilidade CLR para chamar APIs simples não gerenciadas do código gerenciado. A invocação de plataforma está disponível em todos os idiomas gerenciados.
RCW (runtime callable wapper) Um tipo especial de wrapper criado pela camada de interoperabilidade CLR em torno de objetos COM que são ativados do código gerenciado. Um RCW oculta as diferenças entre os modelos de objeto GERENCIADO e COM fornecendo marshaling de dados, gerenciamento de tempo de vida, gerenciamento de identidades, tratamento de erros, transições corretas de apartment e threading e assim por diante.
Código não gerenciado O código executado fora do CLR é chamado de "código não gerenciado". Componentes COM, componentes ActiveX e funções de API Win32 são exemplos de código não gerenciado.