I need to make a DLL written in C accessible to C# programs. I wrote a wrapper DLL in C# that wraps every C interface function. I came out with a code which is functional but eventually crashes with the following message:
Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem in 'D:\WrapperTest\bin\x64\Debug\WrapperTest.exe'.
Additional information: A callback was made on a garbage collected delegate of type 'vJoyInterfaceWrap!vJoyInterfaceWrap.vJoy+WrapFfbCbFunc::Invoke'.
The part that is responsible to the crash is related to a callback function that the C# code registers with the DLL. The crash occurs when the DLL calls (or returns) from the registered callback function.
C DLL Interface:
// Definition of callback function prototype
// Parameter 1: Pointer to a data structure to be used inside the CB function
// Parameter 2: Pointer to user-defined data passed during registration
typedef void (CALLBACK *FfbGenCB)(PVOID, PVOID);
// Registration of CB function.
// Parameter cb is a pointer to the callback function.
// Parameter data is a pointer to user-defined data
VOID __cdecl FfbRegisterGenCB(FfbGenCB cb, PVOID data);
C# Interface:
I'd like the user-defined data to be an object (rather than an IntPtr). To do that I encapsulate the user's callback function with a predefined callback function that converts IntPtr to object. Earlier during registration, I register the predefined callback function and convert the user-defined data (a C# object) to IntPtr.
// The user-defined CB function is of type FfbCbFunc
// FfbCbFunc is defined:
public delegate void FfbCbFunc(IntPtr data, object userData);
// The registration of the predefined callback function _WrapFfbCbFunc is done by calling
// function FfbRegisterGenCB:
public void FfbRegisterGenCB(FfbCbFunc cb, object data)
{
// Convert object to pointer
GCHandle handle1 = GCHandle.Alloc(data);
// Apply the user-defined CB function
_g_FfbCbFunc = new FfbCbFunc(cb);
WrapFfbCbFunc wf = new WrapFfbCbFunc(_WrapFfbCbFunc);
_FfbRegisterGenCB(wf, (IntPtr)handle1);
}
Here are additional definitions and declaration:
// Placeholder for user defined callback function
private static FfbCbFunc _g_FfbCbFunc;
// predefined callback function that encapsulates the user-defined callback function
public delegate void WrapFfbCbFunc(IntPtr data, IntPtr userData);
public void _WrapFfbCbFunc(IntPtr data, IntPtr userData)
{
// Convert userData from pointer to object
GCHandle handle2 = (GCHandle)userData;
object obj = handle2.Target as object;
// Call user-defined CB function
_g_FfbCbFunc(data, obj);
}