RCode

a software development blog by Bojan Resnik

Posts Tagged ‘cli’

Passing C++/CLI delegate to native code

Posted by Bojan Resnik on May 18, 2009

Recently I had to interface a C++/CLI assembly with a native DLL written in C. This is mostly straightforward, but the C DLL could raise an internal event and provided a way to have the application notified of this event. In order to be informed, the application has to register a callback function that will be invoked by the DLL when the event is raised. The registration function is declared like this:

typedef void (__stdcall* EventCallback)();
void RegisterCallback(EventCallback callback);

Using an ordinary function for the callback would be easy, but I wanted to use a .NET delegate so that I could convert the native event into a .NET event. This scenario also turns out to be supported by .NET. All you need to take care of is to prevent the delegate from being moved or collected by the garbage collector.

public delegate void EventDelegate();

ref class NativeInterface
{
public:
    NativeInterface()
    {
        // Create the delegate from a member function
        nativeCallback_ = gcnew EventDelegate(this, &NativeInterface::Callback);

        // As long as this handle is alive, the GC will not move or collect the delegate
        // This is important, because moving or collecting invalidate the pointer
        // that is passed to the native function below
        delegateHandle_ = GCHandle::Alloc(nativeCallback_);

        // This line will actually get the pointer that can be passed to
        // native code
        IntPtr ptr = Marshal::GetFunctionPointerForDelegate(nativeCallback_);

        // Convert the pointer to the type required by the native code
        RegisterCallback( static_cast<EventCallback>(ptr.ToPointer()) );
    }

    !NativeInterface()
    {
        // Free the handle to the delegate, allowing GC to collect
        // the delegate
        if (delegateHandle_.IsAllocated)
            delegateHandle_.Free();
    }

private:
    GCHandle delegateHandle_;
    EventDelegate^ nativeCallback_;

    void Callback()
    {
        Console::WriteLine("Native event raised");
    }
};

kick it on DotNetKicks.comShout it

Posted in .NET, C++/CLI | Tagged: , , | 8 Comments »