3

在我的 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() 一起工作?使用普通的旧函数指针没有问题。

4

1 回答 1

2

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

您需要使用:

typedef void (*MYCALLBACK)();

注意这个函数是cdecl。在 C++ 中将其切换到 stdcall,或者将 C# 委托声明为 cdecl。我希望你知道如何做前者。这是后者的一个例子:

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

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

[DllImport("mydll.dll")]
static extern SetCallbackFunction(MyCallbackFunc cbfunc);
于 2013-09-27T08:56:11.323 回答