Como: ponteiros de função de empacotamento usando PInvoke
Este tópico explica como gerenciados delegados pode ser usado no lugar de ponteiros de função quando interoperar com não gerenciadas funções usando.NET Framework P/Invoke recursos.No entanto, os programadores de Visual C++ são incentivados a usar os recursos de interoperabilidade de C++ em vez disso (quando possível) porque P/Invoke fornece relatórios de erro em tempo de compilar pouco, não é tipo seguro e pode ser entediante implementar.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 ponteiros de funções como argumentos podem ser chamados no código gerenciado com um delegado gerenciado no lugar do ponteiro de função nativa.O compilador automaticamente empacota o delegate para funções não gerenciadas como um ponteiro de função e insere o código necessário transição gerenciado /.
Exemplo
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 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 TakesCallback nativa 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 essa função é executada pela função TakesCallback nativa.
A função gerenciada suprime a coleta de lixo para o delegado gerenciado evitar.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: pura funciona bem.
// 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 # 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.