Passing an array of delegates from C# to C++

Viewed 171

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.

0 Answers
Related