Quite a while back, I posted an article about getting native callbacks to work across AppDomains. Since then, I’ve gotten quite a few comments with varying levels of confusion, and seen a few implementations that appear to have missed something along the way. So I thought it’d be a good idea to post a clarification.
Fundamentally, there are just a few things that you need to remember:
- You cannot access managed objects (including
GCHandles andgcroots) outside of the AppDomain in which they were created. - Each thread which has executed managed code has a “history” linking it to a particular AppDomain. If a thread has never executed managed code before, though, then the first time it tries it will be assumed to be in the first AppDomain.
- Delegates contain information about which AppDomain they should be executed in, so they can “cross the line” when an otherwise pure native thread has no idea which AppDomain it should be using.
- Managed delegates can be turned into native function pointers via the
Marshal::GetFunctionPointerForDelegatemethod. - If you create a function pointer from a delegate, you must keep the delegate alive (by keeping a reference to it) for as long as the native pointer exists.
- Native functions can only have native types as parameters (but they don’t have to just be primitive types). (Actually, there are some limited exceptions to this, which I cover below.)
So, here’s a few example scenarios, to get your head around the ideas. Note that none of these care whether you’re crossing AppDomain boundaries or not (they’re cross-AppDomain-safe, but can be used within the same AppDomain too), so they can also serve as good examples for regular interop scenarios as well.
Continue reading AppDomains and unmanaged callbacks, redux



Recent Comments