I have a DLL from which I need to P/Invoke the following C method:
int DAOpen(HANDLE *hOpen, UNIT *flags, void *callback, void *userData)
Using the P/Invoke Assistant, I’ve come up with the following signature:
[DllImportAttribute("<libName>", EntryPoint="DAOpen")]
static extern int DAOpen(
out IntPtr hOpen,
ref uint flags,
IntPtr callback,
IntPtr userData);
The callback parameter has must correspond to the following C signature:
void CallBack(
int event,
int socket,
struct _iComStructure *plcom,
void *eventData,
void *myData)
which translates to
delegate void CallBack(
int @event,
int socket,
IntPtr plcom,
IntPtr eventData,
IntPtr myData);
Now, I’m doing the call in the following way:
void MyCallBack(int @event, int socket, IntPtr plcom, IntPtr eventData, IntPtr myData)
{
// does nothing for now
}
IntPtr hOpen;
uint flags = 0;
CallBack callBack = MyCallBack;
StringBuilder userData = new StringBuilder(userData.ToString());
int rc = DAOpen(
out hOpen,
ref flags,
Marshal.GetFunctionPointerForDelegate(callBack), Marshal.StringToHGlobalAnsi(userData.ToString()));
The problem I’m having with this code is that it either crashes or I get a FatalExecutionEngineError thrown when I perform a call to DAOpen. I know it must be a marshalling error, but I can’t figure it out…
Thanks for your help!
UPDATE
As was suggested, I tried to pin the callback in the following way:
GCHandle callbackHandle = GCHandle.Alloc(callBack, GCHandleType.Pinned);
I get an ArgumentException with this message:
Object contains non-primitive or non-blittable data
It seems to work fine if I don’t specify the GCHandleType (i.e. I get a handle), but of course the original problem remains.
Is there any reason why I can’t pin the delegate?
Thanks for your input!
Have you taken any steps to ensure the delegate is not garbage collected?
A gen 0 collection could be triggered during your call.
Try either creating a local variable in the calling function,
or manually pinning the delegate in a GC handle.
Update:
Also, look at the calling convention
of the callback in the native API. Is it stdcall?
If not, you can’t use GetFunctionPointerForDelegate, as it
returns a pointer to a native function expecting stdcall arguments.
In that case, instead of us an intptr, use the delegate type and put an “UnmanagedFunctionPointerAttribute” on the delegate definition that specifies the native calling convention.