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
| В | Copy Code |
|---|---|
// 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
| В | Copy Code |
|---|---|
// 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();
} | |
Dhtml editor
Free javascript download