.NET Framework Bookmark and Share   
 index > Common Language Runtime > System.AccessViolationException trying to marshal a struct of function pointers
 

System.AccessViolationException trying to marshal a struct of function pointers

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]-->

GremlinImp
It should work just fine with a class instead of a struct, it does when I try it. While every .NET class automatically inherits Object, the marshaler avoids copying the private fields of Object. When you use Marshal.SizeOf(uglyCallbacks), you should get 8 on a 32-bit OS.

If these callbacks should work after the MP_CallCallback() returns, you'll need to store uglyCallbacks in a class field so it doesn't get garbage collected. And you need to pin the delegate instances so the garbage collector can't move them into another location in the heap.
nobugz
It should work just fine with a class instead of a struct, it does when I try it. While every .NET class automatically inherits Object, the marshaler avoids copying the private fields of Object. When you use Marshal.SizeOf(uglyCallbacks), you should get 8 on a 32-bit OS.

If these callbacks should work after the MP_CallCallback() returns, you'll need to store uglyCallbacks in a class field so it doesn't get garbage collected. And you need to pin the delegate instances so the garbage collector can't move them into another location in the heap.
nobugz

The Signatureon Managed side and Native side is not same.

In the Managed Side:

[DllImport("mylib.dll")]

public static extern void MP_CallCallBack(ref MYCALLBACKS_t callback);

in the Native Side:

extern "C" _declspec(dllexport) void MP_Callback(MYCallBaCKS_t *callbacks)

{

}

the Red Bold Font is not same.

1. if you use ref keyword in the managed side(ref MYCALLBACKS_t callback), you should use MYCallBaCKS_t **callbacks

Managed Side:

[DllImport("mylib.dll")]

public static extern void MP_CallCallBack(ref MYCALLBACKS_t callback);

Native Side:

extern "C" _declspec(dllexport) void MP_Callback(MYCallBaCKS_t **callbacks)

{

}

2. if you dont want to change the native signature, then in the managed side, you should use the class itself,

Managed Side:

[DllImport("mylib.dll")]

public static extern void MP_CallCallBack(MYCALLBACKS_t callback);

Native Side:

extern "C" _declspec(dllexport) void MP_Callback(MYCallBaCKS_t *callbacks)

{

}

Luqunl
This post suggests something else regarding pinning of delegates:


and makes a reference to the following post to make the point that pinning of delegates isunnecessary:

philomath

You can use google to search for other answers

Custom Search

More Threads

• cross domain objects life time
• GetMessage -- Debug assertion failure
• VC++ CLR and C# interoperability
• Caspol.exe registry changes
• RSA : Encrypt with private key and decrypt with public key
• Named Pipes with Interop - invalid / null data in output byte[]
• .NET 2.0 Framework corrupted?
• Performance Problem with very fast restarts of the same program.
• Updating executing assembly
• Cookie Security