This topic demonstrates the marshalling of callbacks and delegates (the managed version of a callback) between managed and unmanaged code using C++.
The following code examples use the
Example
The following example demonstrates how to configure an unmanaged API to trigger a managed delegate. A managed delegate is created and one of the interop methods, (
Notice that is it possible, but not necessary, to pin the delegate using
If a delegate is re-located by a garbage collection, it will not affect the underlaying managed callback, so
В | ![]() |
---|---|
// MarshalDelegate1.cpp // compile with: /clr #include <iostream> using namespace System; using namespace System::Runtime::InteropServices; #pragma unmanaged typedef int (*ANSWERCB)(); int TakesCallback(ANSWERCB fp) { printf_s("[unmanaged] got callback address, calling it...\n"); return fp(); } #pragma managed public delegate int GetTheAnswerDelegate(); int GetNumber() { Console::WriteLine("[managed] callback!"); return 243; } int main() { GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber); GCHandle gch = GCHandle::Alloc(fp); IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp); ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer()); Console::WriteLine("[managed] sending delegate as callback..."); // force garbage collection cycle to prove // that the delegate doesn't get disposed GC::Collect(); int answer = TakesCallback(cb); // release reference to delegate gch.Free(); } |
The following example is similar to the previous example, but in this case the provided function pointer is stored by the unmanaged API, so it can be invoked at any time, requiring that garbage collection be suppressed for an arbitrary length of time. As a result, the following example uses a global instance of
В | ![]() |
---|---|
// MarshalDelegate2.cpp // compile with: /clr #include <iostream> using namespace System; using namespace System::Runtime::InteropServices; #pragma unmanaged typedef int (*ANSWERCB)(); static ANSWERCB cb; int TakesCallback(ANSWERCB fp) { cb = fp; if (cb) { printf_s("[unmanaged] got callback address (%d), calling it...\n", cb); return cb(); } printf_s("[unmanaged] unregistering callback"); return 0; } #pragma managed public delegate int GetTheAnswerDelegate(); int GetNumber() { Console::WriteLine("[managed] callback!"); static int x = 0; return ++x; } static GCHandle gch; int main() { GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber); gch = GCHandle::Alloc(fp); IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp); ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer()); Console::WriteLine("[managed] sending delegate as callback..."); int answer = TakesCallback(cb); // possibly much later (in another function)... Console::WriteLine("[managed] releasing callback mechanisms..."); TakesCallback(0); gch.Free(); } |