Hi,
I have a C DLL that exports a function which takes a struct of function pointers as an argument. I'm tring to run some demo code to prove that we can wrap this DLL in .NET. Actually calling the callback functions causes a System.AccessViolationException with the message "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Here is some equivalent sample code:
//C DLL code:
typedef void (*MY_CALLBACK1)(int input);
typedef void (*MY_CALLBACK2)(int input);
typedef struct _tagMYCALLBACKS_t
{
MY_CALLBACK1 m_callOne;
MY_CALLBACK2 m_callTwo;
} MIKECALLBACKS_t;
extern "C" __declspec(dllexport) void MP_CallCallback(MYCALLBACKS_t* callbacks)
{
callbacks->m_callOne(77);
callbacks->m_callTwo(88);
}
OK, So here is the C# code I have:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MY_CALLBACK1(int param);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MY_CALLBACK2(int param);
[StructLayout(LayoutKind.Sequential)]
public class MYCALLBACKS_t
{
public MY_CALLBACK1 callback1;
public MY_CALLBACK2 callback2;
}
[DllImport("mylib.dll")]
public static extern void MP_CallCallback(ref MYCALLBACKS_t callback);
Finally, here is the test client code:
public static void ShowNumber(int intput)
{
MessageBox.Show(intput.ToString());
}
MYCALLBACKS_t uglyCallbacks = new MYCALLBACKS_t();
uglyCallbacks.callback1 = new MY_CALLBACK1(ShowNumber);
uglyCallbacks.callback2 = new MY_CALLBACK2(ShowNumber);
//Here is where I get the exception:
MP_CallCallback(ref uglyCallbacks);
So, I've been playing around with my code while I wrote up this post. If I change the managed declaration of the MYCALLBACKS_t struct to a 'struct' instead of a 'class' everything works just fine (see the 'middle' chunk of code). My question then is, what is going on under the hood that would cause a struct mapped as a class to give this error but a struct mapped as a struct to work just fine? I mean, I've read MSDN articles where unmanaged structs are mapped as managed classes ... that's why I wrote my code that way in the first place. I would expect classes to be longer lived and therefore better containers for callbacks like these. In any case, this has become an academic issue, however, I'd love some feedback on what folks think is going on here.
Thanks,
- Grem <!--[if !supportLineBreakNewLine]-->
<!--[endif]-->