Partilhar via


Como: PInvoke usando de ponteiros de função Marshal

Este tópico explica os delegados como gerenciados pode ser usado no lugar de ponteiros de função quando interoperar com o uso de funções não gerenciadas.NET Framework de P/Invoke recursos. Entretanto, os programadores de Visual C++ são incentivados a usar os recursos de interoperabilidade de C++ em vez disso, (quando possível), porque fornece relatórios de erro de tempo de compilação pouco P/Invoke, não é um tipo seguro e pode ser entediante implementá. Se a API não gerenciada é empacotada como uma DLL e o código-fonte não está disponível, P/Invoke é a única opção. Caso contrário, consulte os seguintes tópicos:

APIs não gerenciadas que levam os ponteiros de funções como argumentos podem ser chamados do código gerenciado com um delegado gerenciado no lugar do ponteiro de função nativa. O compilador automaticamente empacota o delegado para funções não gerenciadas como um ponteiro de função e insere o código necessário de transição gerenciados/não gerenciados.

Exemplo

O código a seguir consiste em um não gerenciado e um módulo gerenciado. O módulo de não gerenciado é uma DLL que define uma função chamada TakesCallback que aceita um ponteiro de função. Esse endereço é usado para executar a função.

O módulo gerenciado define um delegado que é empacotado para código nativo como um ponteiro de função e usa o DllImportAttribute atributo para expor a função nativa do TakesCallback para código gerenciado. A função main, uma instância do delegado é criada e passada para a função TakesCallback. A saída do programa demonstra que essa função seja executada pela função nativa do TakesCallback.

Suprime a coleta de lixo para o delegado gerenciado impedir que a função gerenciada.Coleta de lixo do NET Framework de realocar o delegado enquanto executa a função nativa.

O módulo gerenciado é compilado com /clr mas /clr: puro também o works.

// TraditionalDll5.cpp
// compile with: /LD /EHsc
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif

extern "C" {
   /* Declare an unmanaged function type that takes two int arguments
      Note the use of __stdcall for compatibility with managed code */
   typedef int (__stdcall *CALLBACK)(int);
   TRADITIONALDLL_API int TakesCallback(CALLBACK fp, int);
}

int TakesCallback(CALLBACK fp, int n) {
   printf_s("[unmanaged] got callback address, calling it...\n");
   return fp(n);
}

// MarshalDelegate.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;

public delegate int GetTheAnswerDelegate(int);
public value struct TraditionalDLL {
   [DllImport("TraditionalDLL5.dll")]
   static public int TakesCallback(GetTheAnswerDelegate^ pfn, int n);
};

int GetNumber(int n) {
   Console::WriteLine("[managed] callback!");
   static int x = 0;
   ++x;
   return x + n;
}

int main() {
   GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber);
   pin_ptr<GetTheAnswerDelegate^> pp = &fp;
   Console::WriteLine("[managed] sending delegate as callback...");

   int answer = TraditionalDLL::TakesCallback(fp, 42);
}

Observe que nenhuma parte da DLL é exposto para código gerenciado usando o # tradicional de diretiva de inclusão. Na verdade, a DLL é acessada em tempo de execução somente para problemas com funções importadas com DllImportAttribute não serão detectadas em tempo de compilação.

Consulte também

Outros recursos

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