簡體   English   中英

P/Invoke - 將委托編組為函數指針 + void*

[英]P/Invoke - Marshaling delegate as function pointer + void*

C 中一個相當常見的習慣用法是使用多態閉包將其表示為兩個參數,一個函數指針和 void 指針(作為參數之一傳遞給函數指針。

取自GPGME庫的示例:

typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook,
                                                const char *uid_hint,
                                                const char *passphrase_info,
                                                int prev_was_bad, 
                                                int fd);

void gpgme_set_passphrase_cb (gpgme_ctx_t ctx,
                              gpgme_passphrase_cb_t cb, 
                              void *hook_value);

從概念上講,函數指針加上 void 指針表示與 C# 中的委托(閉包)相同的事物。 在進行這種 P/Invoke 調用時,是否有一種很好的規范方式來編組委托?

在進行這種 P/Invoke 調用時,是否有一種很好的規范方式來編組委托?

您不需要使用void*參數,因為 C# 委托是一個閉包。 傳遞IntPtr.Zero作為鈎子值。 您的 C# 委托仍然需要接受void*參數,但它可以簡單地忽略它,因為它不需要它。

您實際上可以將委托從 C# 傳遞到 C 函數指針。 您應該使用[UnmanagedFunctionPointer]屬性裝飾此委托。 這就是我們如何包裝一個帶有函數指針的 C 方法:

C方法:

__declspec(dllexport) globle int EnvAddRouterEx(int (*queryFunction)(void*, char*))

P\\Invoke 方法:

[DllImport(clipsDllLocation, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern int EnvAddRouterEx(ClipsRouterQueryFunctionDelegate queryFunction);

P\\Invoke 委托:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int ClipsRouterQueryFunctionDelegate(IntPtr theEnv, string logicalName);

其他答案是正確的,但是,我只想附加一些 C#9 信息:

現在可以在 C# 中使用函數指針如下(需要啟用unsafe ):

static int add(int a, int b) => a + b;

delegate*<int, int, int> pointer = &add;
int result = add(40, 2);

上面代碼片段中的函數指針在內部被處理為nint (或IntPtr )並且可以在 P/Invoke 聲明中使用:

[DllImport("my_library.dll")]
static extern int CallMyCallback(delegate*<int, int, int> callback, int arg1, int arg2);

my_library.dll的示例 C++ 實現可以是:

extern "C" __declspec(dllexport) int CallMyCallback(
    int (*callback)(int, int),
    int arg1,
    int arg2)
{
    return callback(arg1, arg2);
}

CallMyCallback可以按如下方式使用(來自 C#):

static int multiply(int a, int b) => a * b;

int result = CallMyCallback(&multiply, -12, 7);

注意:此語言功能不能與 lambda 表達式或非靜態方法一起使用(實例方法需要傳遞隱式this指針)。


官方文檔尚不存在,但您可以查看 C#9 GitHub issue/tracker: https : //github.com/dotnet/csharplang/issues/191

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM