65.9K
CodeProject is changing. Read more.
Home

Pass C# Delegate as Callback to C++

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (7 votes)

May 29, 2012

CPOL

1 min read

viewsIcon

44063

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

History

  • 29th May, 2012: Tip uploaded