Partilhar via


Como: realizar realizar marshaling ponteiros Embedded usando PInvoke

Funções que são implementadas em DLLs não gerenciadas podem ser chamadas no código gerenciado usando a funcionalidade de invocação de plataforma (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, ao contrário de outras linguagens. NET, Visual C++ fornece uma alternativa para o P/Invoke.Para obter mais informações, consulte Usando a interoperabilidade de C++ (PInvoke implícita) e Como: realizar realizar marshaling ponteiros Embedded usando interoperabilidade C++.

Exemplo

Passar estruturas para código nativo requer que um gerenciado estrutura que é equivalente em termos de layout de dados para a estrutura nativa é criada.No entanto, as estruturas que contêm ponteiros exigem tratamento especial.Para cada ponteiro incorporado na estrutura nativa, a versão gerenciada da estrutura deve conter uma instância do IntPtr Digite. Além disso, memória para essas instâncias deve ser explicitamente alocada, inicializado e lançada usando o AllocCoTaskMem, StructureToPtr, e FreeCoTaskMem métodos.

O código a seguir consiste em um não-gerenciados e um módulo gerenciado.O módulo não gerenciado é uma DLL que define uma função que aceite uma estrutura chamada ListString 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 é equivalente a ListStruct nativo, exceto pelo fato de que dois * é representado com uma IntPtr instância. Antes de chamar TakesListStruct, a função main aloca e inicializa a memória que faz referência a esse campo.

O módulo gerenciado é compilado com/CLR, mas com/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 seja exposta a código gerenciado usando o # tradicional diretiva include.Na verdade, a DLL é acessada na execução time apenas, portanto, problemas com funções importados com DllImportAttribute não serão detectados no momento da compilar.

Consulte também

Outros recursos

Usar PInvoke Explicit no C++ (atributo DllImport)