将托管函数传递给使用std :: function()的非托管函数

时间:2013-09-27 06:58:14

标签: c# c++ pinvoke

在我的C ++代码中,回调函数表示为std :: function()obj,而不是更常见的函数指针构造。

typedef std::function<void()> MYCALLBACK;

C ++中的回调函数通过以下方式设置:

MYCALLBACK myCBFunc; // some member variable
void SetCallbackFunction(MYCALLBACK cbFunc)
{
  myCBFunc = cbFunc;
}
在C#中

delegate void MyCallbackFunc(); // delegate matching the c++ callback sig

// method matching the call back sig
void foo()
{ }

[DllImport("mydll.dll")]
static extern SetCallbackFunction(MyCallbackFunc cbfunc);

// set the callback
MyCallbackFunc cb = foo;
SetCallbackFunction(cb); // crash here

编译好,但运行时遇到AccessViolationException崩溃。 我最初认为这是因为MYCALLBACK obj在堆栈上,并且需要通过引用传递并更改签名以匹配但它仍然崩溃,即。

MYCALLBACK myCBFunc; // some member variable
void SetCallbackFunction(MYCALLBACK& cbFunc)
{
  myCBFunc = cbFunc;
}

[DllImport("mydll.dll")]
static extern SetCallbackFunction(ref MyCallbackFunc cbfunc);

// set the callback
MyCallbackFunc cb = foo;
SetCallbackFunction(ref cb); // crash here

我如何使用std :: function()?使用普通的旧函数指针没有问题。

1 个答案:

答案 0 :(得分:2)

std::function<void()>是一个类模板。它看起来像一个函数,因为类重载operator()。因此,std::function<void()>是一个类意味着它不是与非托管函数指针二进制兼容。

您需要使用:

typedef void (*MYCALLBACK)();

请注意,此函数是cdecl。在C ++中将其切换为stdcall,或将C#delegate声明为cdecl。我希望你知道怎么做前者。以下是后者的一个例子:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void MyCallbackFunc();

你的pinvoke也是错误的,因为它不应该将回调作为ref参数传递。它应该是:

[DllImport("mydll.dll")]
static extern SetCallbackFunction(MyCallbackFunc cbfunc);