I need to pass an array of delegates from C# to C++.
I can pass a single delegate like this:
In C#:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public delegate IntPtr MyDelegate(string inStringParam, out int outIntParam, out string outStringParam);
In C++:
typedef void* (*MyCallback)(w_char_t inStringParam, int* outIntParam, wchar_t* outStringParam);
I’m passing a C# struct with multiple parameters, including this one:
[MarshalAs(UnmanagedType.FunctionPtr)] internal MyDelegate MyHandler;
In C++, I receive the parameters, including this one:
MyCallback* MyHandler;
And reference it, like this:
(MyCallback)initParams->MyHandler;
Works like a charm.
Now, instead of passing just one delegate, I need to pass X delegates. I’ve tried a LOT of things, a couple of man-days worth of things, but no joy. The most straightforward approach seems to be a fixed size, single dimension array. From what I can gather, this should work in my C# struct:
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.FunctionPtr, SizeConst = 32)]
internal MyDelegate[] MyHandlers;
I initialize the array when I ‘new up’ the struct:
private NativeParameters _startupParameters = new NativeParameters { MyHandlers = new MyDelegate[32] };
Then, I add my delegate implementation to the first spot in the array:
_startupParameters.MyHandlers[0] = OnMyEvent;
On the C++ side, I change my struct to have a fixed size array:
MyCallback* MyHandlers[32];
And reference the first item like this:
(MyCallback)initParams->MyHandlers[0];
Everything compiles, I do get a pointer when I reference the callback, all of the other values on the struct are still working correctly, but when I invoke the callback, I get:
System.AccessViolationException
HResult=0x80004003
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
It appears to do with .NET Interop (though I can’t prove it). I can successfully pass an array of simpler types like ints or even strings using the same approach:
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPWStr, SizeConst = 32)]
internal string[] MyStrings;
Those all work. The exception only comes up when I try to pass an array of delegates (technically, pointers to delegates) and try to invoke the callback.
Any ideas are appreciated.