Como: empacotamento incorporado ponteiros usando PInvoke
Funções que são implementadas em DLLs não gerenciadas podem ser chamadas de código gerenciado usando a funcionalidade de plataforma invocação (P/Invoke).Se o código-fonte para a DLL não estiver disponível, P/Invoke é a única opção para interoperar.No entanto, diferentemente de outros.NET linguagens, Visual C++ fornece uma alternativa P/Invoke.Para obter mais informações, consulte Usando interoperabilidade C++ (PInvoke implícita) e Como: empacotamento incorporado ponteiros com interoperabilidade de C++.
Exemplo
Passar estruturas para código nativo exige uma estrutura gerenciada é equivalente em termos de layout de dados a estrutura nativa é criada.No entanto, as estruturas que contêm ponteiros exigem tratamento especial.Para cada ponteiro incorporado na estrutura nativa, versão gerenciada da estrutura deve conter uma instância de IntPtr tipo.Além disso, memória para essas instâncias devem ser explicitamente alocadas, inicializado e liberado usando o AllocCoTaskMem, StructureToPtr, e FreeCoTaskMem métodos.
O código a seguir consiste em uma não gerenciado e um módulo gerenciado.O módulo não gerenciado é uma DLL que define uma função que aceita uma estrutura chamada ListString que contém um ponteiro e uma função chamada TakesListStruct.O módulo gerenciado é um aplicativo de linha de comando que importa a função TakesListStruct e define uma estrutura chamada MListStruct que é equivalente a ListStruct nativo, exceto que double * é representado com uma IntPtr instância.Antes de chamar TakesListStruct, a função principal aloca e inicializa a memória que faz referência a esse campo.
O módulo gerenciado é compilado com /clr, mas /clr: pura funciona bem.
// TraditionalDll6.cpp
// compile with: /EHsc /LD
#include <stdio.h>
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
#pragma pack(push, 8)
struct ListStruct {
int count;
double* item;
};
#pragma pack(pop)
extern "C" {
TRADITIONALDLL_API void TakesListStruct(ListStruct);
}
void TakesListStruct(ListStruct list) {
printf_s("[unmanaged] count = %d\n", list.count);
for (int i=0; i<list.count; i++)
printf_s("array[%d] = %f\n", i, list.item[i]);
}
// EmbeddedPointerMarshalling.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;
[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MListStruct {
int count;
IntPtr item;
};
value struct TraditionalDLL {
[DllImport("TraditionalDLL6.dll")]
static public void TakesListStruct(MListStruct);
};
int main() {
array<double>^ parray = gcnew array<double>(10);
Console::WriteLine("[managed] count = {0}", parray->Length);
Random^ r = gcnew Random();
for (int i=0; i<parray->Length; i++) {
parray[i] = r->NextDouble() * 100.0;
Console::WriteLine("array[{0}] = {1}", i, parray[i]);
}
int size = Marshal::SizeOf(double::typeid);
MListStruct list;
list.count = parray->Length;
list.item = Marshal::AllocCoTaskMem(size * parray->Length);
for (int i=0; i<parray->Length; i++) {
IntPtr t = IntPtr(list.item.ToInt32() + i * size);
Marshal::StructureToPtr(parray[i], t, false);
}
TraditionalDLL::TakesListStruct( list );
Marshal::FreeCoTaskMem(list.item);
}
Observe que nenhuma parte da DLL é exposto para código gerenciado usando # tradicional incluir diretiva.Na verdade, a DLL é acessada no tempo de execução somente para problemas com funções importados com DllImportAttribute não serão detectados em tempo de compilação.