共用方式為


如何:使用 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 匯入的函式問題。

另請參閱

在 C++ 中使用明確的 P/Invoke ( DllImport 屬性)