Partilhar via


Como realizar marshaling de ponteiros inseridos usando PInvoke

As funções que são implementadas na DLL não gerenciado podem ser chamadas de código gerenciado usando a funcionalidade de invocação de plataforma (P/Invoke). Se o código-fonte do DLL não estiver disponível, P/Invoke é a única opção para interoperar. No entanto, diferentemente de outras linguagens .NET, Visual C++ fornece uma alternativa a P/Invoke. Para obter mais informações, consulte Usando interop C++ (PInvoke implícito) e Como realizar marshaling de ponteiros inseridos usando interop C++.

Exemplo

Passe estruturas em código nativo que requer uma estrutura gerenciado que é equivalente em termos de layout de dados à estrutura nativo é criada. No entanto, as estruturas que contêm ponteiros exigem tratamento especial. Para cada ponteiro inserido na estrutura nativo, a versão gerenciado da estrutura deve conter uma instância do tipo de IntPtr . Além disso, a memória para essas instâncias deve ser atribuída explicitamente, inicializado, e liberada usando AllocCoTaskMem, StructureToPtr, e os métodos de FreeCoTaskMem .

O código a seguir consiste em um módulo não gerenciado e 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 de TakesListStruct e define uma estrutura chamada MListStruct que é equivalente a ListStruct nativo com exceção de que o double* é representado por uma instância de IntPtr . Antes de chamar TakesListStruct, a função principal e atribui inicializa a memória que faz referência a esse campo.

O módulo gerenciado é compilado com /clr, mas trabalho de /clr:pure também.

// 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 está exposta ao código gerenciado usando a diretiva tradicional de #include. De fato, a DLL é acessado em tempo de execução, apenas assim que os problemas com as funções com DllImportAttribute importadas não serão detectados em tempo de compilação.

Consulte também

Outros recursos

Usando PInvoke explícito em C++ (atributo DllImport)