2

I've seen the possible duplicate but the semantics are slightly different so I havent' been able to get it working until now. I'm not even sure it is really comparable to the pure c-function pointer style, which I've already used in different projects.

I have a DLL which defines a native C++ callback like this:

class NativeClass
{

// Native Callback Handler class, internal definition
class Callback
{
public:
  // Constructor
  Callback() {}
  // Destructor
  virtual ~Callback() {}

  // Callback functions
  virtual void Handler() {}
};

SetCallback(Callback* p)
{
   ...
}
...

The DLL then consumes and fires the Callback by this function:

SetCallBack(NativeClass::Callback* p);

So when I'm writing my C++/CLI wrapper, how can I pass a reference to a managed object exposing such a callback handler.

Is something like this generally not possible or how would I have to handle that correctly ? I've tried the following now according to the MSDN documentation and other SO answers:

typedef (__stdcall *NATIVE_CALLBACK)(void);

public delegate void ManagedCallback();

...

public ref class Wrapper
{
public:

Callback*    _CBHandlerNative;
NativeClass* nc; 

Wrapper()
{
    _CBHandlerNative = new NativeClass::Callback();
    _nc              = new NativeClass();


    // try assigning function pointer, but fails 

   IntPtr ip = Marshal::GetFunctionPointerForDelegate(gcnew ManagedCallback(this, &Wrapper::ToBeCalled));
   _CBHandlerNative->Handler = static_cast<NATIVE_CALLBACK>(ip.ToPointer());

     _nc->SetCallback(_CBHandlerNative);

}

// managed handler
void ToBeCalled()
{
  ...
}
Florian Storck
  • 509
  • 8
  • 22
  • There is a page about this in MSDN [documentation](http://msdn.microsoft.com/en-us/library/367eeye0%28v=vs.100%29.aspx) – Jairo Jun 18 '14 at 10:54
  • @Jairo: looks promising, but does it also works for callback objects? I only see a callback Function, not an object with several functions. Or do I simply assign the Pointer to my wrapper function for each virtual function in the callback object ? – Florian Storck Jun 18 '14 at 10:59

1 Answers1

1

I have now a solution, which seems to be working correctly:

First, I'm defining a native proxy class for holding the callbacks:

public class CbProxy : Callback
{
public:
   NATIVE_CALLBACK _cbHandler;

   virtual void Handler()
   {
       if(_cbHandler != NULL)
           _cbHandler();
   }
}

Now I can attach the managed delegate to the Handler proxy and pass it to the native DLL.

public delegate void ManagedCallback ();

ManagedCallback^ mcb = gcnew ManagedCallback (this, &Wrapper::ToBeCalled);

IntPtr ip = Marshal::GetFunctionPointerForDelegate(mcb);

_pCbProxy->_cbHandler = static_cast<NATIVE_CALLBACK>(ip.ToPointer());

// ensure to keep a reference to the callback, otherwise it
// will be freed 
GC::KeepAlive(mcb);
GC::KeepAlive(ip);


_nc->SetCallback(_pCbProxy);

I'm not sure whether there is a more efficient way, but this works at first sight for me right now.

Florian Storck
  • 509
  • 8
  • 22