Re: Howto use callback functions with a C DLL
- From: Jef Driesen <jefdriesen@xxxxxxxxxxxxxxxxxxx>
- Date: Mon, 28 Jul 2008 15:30:50 +0200
Jef Driesen wrote:
Jef Driesen wrote:I have a C DLL that I want to use from a C# project. The C header file contains these declarations:
typedef void (*callback_t) (const unsigned char *data, unsigned int size, void *userdata);
void myfunction (callback_t callback, void *userdata);
How do I translate this to C#?
I tried with:
delegate void callback_t (Byte[] data, UInt32 size, IntPtr userdata);
[DllImport("mydll.dll")]
static extern void myfunction (callback_t callback, IntPtr userdata);
When calling with myfunction (null, IntPtr.Zero) everything works as expected. But once I start passing a callback function, the application crashes with "Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
void test (Byte[] data, UInt32 size, IntPtr userdata)
{
// Nothing here
}
callback_t callback = new callback_t (test);
myfunction (callback, IntPtr.Zero);
I tried changing the data parameter from a byte array to an IntPtr, but that seems to make no difference. What am I doing wrong? All other functions (without a callback function parameter) work perfect.
I think C# is somehow messing up the stack of my C DLL. If I export this very simple function in my DLL (declared as extern "C" to avoid name mangling):
typedef void (*callback_t) (const unsigned char *data, unsigned int size, void *userdata);
void
myfunction (callback_t callback, void *userdata)
{
unsigned char data[] = {'a', 'b', 'c', 0x00};
printf ("pointer=%p\n", data);
for (unsigned int i = 0; i < 5; ++i) {
printf ("iteration %u\n", i);
if (callback)
callback (NULL, sizeof (data), userdata);
printf ("pointer=%p\n", data);
}
}
And in C#, I use this code:
delegate void callback_t (IntPtr data, UInt32 size, IntPtr userdata);
[DllImport("mydll.dll")]
static extern void myfunction (callback_t callback, IntPtr userdata);
static void test (IntPtr data, UInt32 size, IntPtr userdata)
{
// Nothing here
}
Now, if I call the DLL functon in my main function with the following arguments:
myfunction1 (new callback_t (test), IntPtr.Zero);
I get this output:
pointer=0012F5F0
iteration 0
pointer=0012F5FC
iteration 1
pointer=0012F608
iteration 2
pointer=0012F614
iteration 3
pointer=0012F620
iteration 4
pointer=0012F62C
As you can see, the "data" pointer is increased by 12 bytes after each invocation of the callback function, even if this pointer was never passed to the callback function at all. If I pass "null" for the callback function, the pointer remains the same. If I do the same experiment in a C project, the pointer remains the same, just as it should be. What am I doing wrong?
The problem was caused by the difference in calling convention between
the C DLL (cdecl) and the C# callback function (stdcall). I was able to fix that by changing the calling convention of the callback function to cdecl (.NET 2.x or higher only):
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
public delegate void callback_t (IntPtr data, UInt32 size, IntPtr userdata);
.
- References:
- Howto use callback functions with a C DLL
- From: Jef Driesen
- Re: Howto use callback functions with a C DLL
- From: Jef Driesen
- Howto use callback functions with a C DLL
- Prev by Date: Re: Interop SendMessage : How to pass Structure to be filled by SendMessage
- Next by Date: Re: ILMerge...Why?
- Previous by thread: Re: Howto use callback functions with a C DLL
- Next by thread: XML, LINQ and Server.MathPath
- Index(es):
Relevant Pages
|