Reputation: 231
in my C++ code, a callback function is represented as a std::function() obj, not as the more common function pointer construct.
typedef std::function<void()> MYCALLBACK;
The callback function in C++ is set via:
MYCALLBACK myCBFunc; // some member variable
void SetCallbackFunction(MYCALLBACK cbFunc)
{
myCBFunc = cbFunc;
}
in 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
Compiles OK, but crashes with AccessViolationException when run. I initially thought this is because MYCALLBACK obj is on the stack, and need to pass by reference and changed the signature to match but it still crashes i.e.
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
how do i get this to work with std::function()? No problems using plain old function pointers.
Upvotes: 3
Views: 2202
Reputation: 612964
std::function<void()>
is a class template. It looks like a function because the class overloads operator()
. So, std::function<void()>
being a class means that it is simply not binary compatible with an unmanaged function pointer.
You'll need to use:
typedef void (*MYCALLBACK)();
Note that this function is cdecl. Either switch it to stdcall in your C++, or declare your C# delegate as being cdecl. I expect you know how to do the former. Here's an example of the latter:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void MyCallbackFunc();
Your pinvoke is also wrong in that it should not pass the callback as a ref
parameter. It should be:
[DllImport("mydll.dll")]
static extern SetCallbackFunction(MyCallbackFunc cbfunc);
Upvotes: 2