Usando interop do C++ (PInvoke implícito)
Ao contrário de outras linguagens do .NET, o Visual C++ dá suporte à interoperabilidade, que permite que código gerenciado e não gerenciado coexistam no mesmo aplicativo e até no mesmo arquivo (com os pragmas managed, unmanaged). Isso permite que os desenvolvedores do Visual C++ integrem a funcionalidade do .NET a aplicativos do Visual C++ existentes sem comprometer o restante do aplicativo.
Você também pode chamar funções não gerenciadas de um compiland gerenciado usando dllexport, dllimport.
PInvoke implícito é útil quando você não precisa especificar como os parâmetros de função serão empacotados ou qualquer um dos outros detalhes que podem ser especificados ao chamar explicitamente DllImportAttribute.
O Visual C++ fornece duas maneiras para funções gerenciadas e não gerenciadas interoperarem:
O PInvoke explícito é compatível com o .NET Framework e está disponível na maioria das linguagens .NET. Mas, como o nome indica, a Interoperabilidade do C++ é específica do Visual C++.
Interoperabilidade C++
A Interoperabilidade do C++ fornece melhor segurança de tipo e a implementação dela normalmente é menos tediosa. No entanto, a Interoperabilidade do C++ não será uma opção se o código-fonte não gerenciado não estiver disponível ou não for destinado para projetos multiplataforma.
Interoperabilidade COM C++
Os recursos de interoperabilidade compatíveis com o Visual C++ oferecem uma vantagem específica em relação a outras linguagens .NET quando se trata de interoperação com componentes COM. Em vez de se limitar às restrições do Tlbimp.exe (Importador de Biblioteca de Tipos) do .NET Framework, como suporte limitado para tipos de dados e exposição obrigatória de cada membro de cada interface COM, a interoperabilidade do C++ permite que os componentes COM sejam acessados à vontade e não exige assemblies de interoperabilidade separados. Ao contrário do Visual Basic e do C#, o Visual C++ pode usar objetos COM diretamente usando os mecanismos COM usuais (como CoCreateInstance e QueryInterface). Isso é possível devido aos recursos de interoperabilidade do C++ que fazem com que o compilador insira automaticamente o código de transição para passar de funções gerenciadas para não gerenciadas e depois vice-versa.
Usando a interoperabilidade do C++, os componentes COM podem ser usados da maneira usual ou podem ser encapsulados dentro de classes C++. Essas classes wrapper são chamadas de CRCWs (Runtime Callable Wrappers personalizados) e têm duas vantagens sobre o uso de COM diretamente no código do aplicativo:
A classe resultante pode ser usada de linguagens de programação diferentes do Visual C++.
Os detalhes da interface COM podem ser ocultos do código do cliente gerenciado. Os tipos de dados do .NET podem ser usados no lugar de tipos nativos, e os detalhes do marshaling de dados podem ser executados de maneira transparente dentro do CRCW.
Independentemente de COM ser usado diretamente ou por meio de um CRCW, é preciso realizar marshal de tipos de argumento diferentes de tipos simples e blittable.
Tipos blittable
Para APIs não gerenciadas que usam tipos simples e intrínsecos (consulte Tipos Blittable e Não Blittable), nenhuma codificação especial é necessária porque esses tipos de dados têm a mesma representação na memória, mas tipos de dados mais complexos exigem marshaling de dados explícito. Para obter um exemplo, confira Como chamar DLLs nativas a partir do código gerenciado usando PInvoke.
Exemplo
// vcmcppv2_impl_dllimp.cpp
// compile with: /clr:pure user32.lib
using namespace System::Runtime::InteropServices;
// Implicit DLLImport specifying calling convention
extern "C" int __stdcall MessageBeep(int);
// explicit DLLImport needed here to use P/Invoke marshalling because
// System::String ^ is not the type of the first parameter to printf
[DllImport("msvcrt.dll", EntryPoint = "printf", CallingConvention = CallingConvention::Cdecl, CharSet = CharSet::Ansi)]
// or just
// [DllImport("msvcrt.dll")]
int printf(System::String ^, ...);
int main() {
// (string literals are System::String by default)
printf("Begin beep\n");
MessageBeep(100000);
printf("Done\n");
}
Begin beep
Done
Nesta seção
Como realizar marshaling de cadeias de caracteres ANSI usando interop do C++
Como realizar marshaling de cadeias de caracteres Unicode usando interop do C++
Como realizar marshaling de cadeias de caracteres COM usando interop do C++
Como realizar marshaling de estruturas usando interop do C++
Como realizar marshaling de retornos de chamada e delegados usando interop do C++
Como realizar marshaling de ponteiros inseridos usando interop do C++
Como converter a cadeia de caracteres char * na matriz System::Byte
Como converter System::String em uma cadeia de caracteres padrão
Como converter uma cadeia de caracteres padrão em System::String
Como carregar recursos não gerenciados em uma matriz de bytes
Como manter a referência para o tipo de valor no tipo nativo
Como manter a referência do objeto na memória não gerenciada
Para obter informações sobre como usar delegados em um cenário de interoperabilidade, confira delegado (Extensões de Componente C++).