Pass C# Delegate as Callback to C++






4.91/5 (7 votes)
This tip shows how to pass a delegate to a C++ exported DLL function from C#
Introduction
This tip mainly shows how to pass a C# delegate to C++ with the aid of exported DLL functions.
The C++ version of the callback (which is a delegate in C#)
typedef void (__stdcall *fnNotify)(int notifyCode, NotifyStruct* notifyInfo);
How the delegate signature looks like in C#
public delegate void
DelegateNotify(int notifyCode, ref DLLLoader.NotifyStruct notifyInfo);
As you should be already aware, you have to instantiate the delegate by code which looks something like this:
new DelegateNotify(fnNotify); // where fnNotify is a method
//which exactly has the same signature as the delegate
Let's take a look at the function that would be accepting the callback..
The C++ exported DLL function which takes the callback as argument
extern "C" DLL_IMPORTEXPORT void SetNotifyCallBack(fnNotify callBack);
The C# version of the imported C++ function
[DllImport("TestDLL.dll", CharSet = CharSet.Auto)]
public static extern void SetNotifyCallBack(MulticastDelegate callback);
The above definition is inside a DLLLoader
class.
Note the MulticaseDelegate
argument type which actually does the trick of converting a delegate to a passable C++ callback.
Points of Interest
In the above C++ exported function, the callback takes a simple structure which contains notification data. So this tip also shows a way to marshall simple structures from C++ to C# through the callback function. So here is a little about marshalling simple structures to and fro C# and C++).
The structure to be marshalled (C# version)
public class DLLLoader
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct NotifyStruct
{
public int notifyHeader;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string notifyDescription;
}
//...
[DllImport("TestDLL.dll", CharSet = CharSet.Auto)]
public static extern void SetNotifyCallBack(MulticastDelegate callback);
}
The definition of the same in C++
typedef struct _tagNotifyStruct
{
int notifyHeader;
wchar_t notifyDescription[NGH_EXPLORERITEM_MAXLEN];
}NotifyStruct;
Now we have defined the structure which is consistent both in C++ and C# (they have to be consistent of course, otherwise they won't work), let's turn our attention to the real thing... passing the Callback (delegate in C#).. to C++
Finally .. Create Delegate and Pass to C++
DelegateNotify callback = new DelegateNotify(fnNotify);
DLLLoader.SetCallBack(callback);
Acknowledgements
- Mr. Saiful Alam of Enosis Solutions for showing me the way to do it
- Ridwan Al Iqbal of Enosis Solutions on tipping about how to improve the tip
History
- 29th May, 2012: Tip uploaded