如何:使用 P/Invoke 封送處理函式指標
使用 .NET Framework P/Invoke 功能與 Unmanaged 函式互操作時,可以使用 Managed 委派取代函式指標。 不過,建議您盡可能改用 C++ Interop 功能。 P/Invoke 提供很少的編譯時間錯誤報告、不是類型安全,而且可能很繁瑣來實作。 如果 Unmanaged API 封裝為 DLL 且原始碼無法使用,P/Invoke 是唯一的選項。 否則,請參閱下列文章:
使用 Managed 委派取代原生函式指標,即可從 Managed 程式代碼呼叫採用函式指標做為自變數的 Unmanaged API。 編譯程式會自動將委派封送處理至 Unmanaged 函式做為函式指標。 它會插入必要的 Managed/Unmanaged 轉換程式代碼。
範例
下列程式代碼包含 Unmanaged 和 Managed 模組。 Unmanaged 模組是定義可接受函式指標之函式的 TakesCallback
DLL。 這個位址是用來執行函式。
// 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);
}
Managed 模組會將封送處理至機器碼的委派定義為函式指標。 它會使用 DllImportAttribute 屬性向Managed程式代碼公開原生 TakesCallback
函式。 在函式中 main
,會建立委派的實例,並傳遞至函 TakesCallback
式。 程序輸出示範此函式是由原生 TakesCallback
函式執行。
Managed 函式會隱藏 Managed 委派的垃圾收集,以防止 .NET Framework 垃圾收集在原生函式執行時重新放置委派。
// 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);
}
DLL 的一部分不會使用傳統 #include
指示詞向 Managed 程式代碼公開。 事實上,DLL 只會在運行時間存取,因此無法在編譯時期偵測使用 DllImportAttribute 匯入的函式問題。