How do non-static callbacks work from native code?

2019-05-02 11:44发布

It's a bit odd asking this question, because I have code that seems like it shouldn't work, but it does, and although I'm not complaining, I'd like to confirm why? LOL

Simply, I have a C++ native DLL (no CLR/managed support at all) that takes a call-back from C# code. The native side stores an stdcall callback function, which is supplied by the C# side. I always thought the callback METHOD (in C#) had to be static, but non-static and lambda expression BOTH work JUST FINE!? How is the "this" pointer being marshaled from native code? I always thought that native code only stores non-instance function pointers?

Now, I did find an article where some guy emitted IL code to "bridge" between native and non-static managed callbacks. I also noticed this depreciated method: "Marshal.GetUnmanagedThunkForManagedMethodPtr()". The method is no longer supported, which I'm assuming means it is built in?

Question summary:

  1. Is thunking now built natively into .NET by emitting IL code? If so, at what version of .NET did this become natively supported?

  2. Is implicit "thunking" supported in Mono as well?

  3. When the IL is emitted for the managed callbacks, what happens when the instance the thunk refers to is deleted? Is the IL removed, or might this lead to a memory "leak" so to speak?

Thanks.

2条回答
趁早两清
2楼-- · 2019-05-02 12:21

The interop marshaller simply marshals a delegate. The delegate can be either an class delegate (no this) or an instance delegate (has a this). From the standpoint of C#, it's just calling a delegate. i.e. the same semantics used to manage this with an instance delegate (e.g. the decoupling of the class instance) is effectively used.

Clearly there's more going on under the covers with other things (like pinning, etc.)--but they're generally unrelated to what you've asked.

查看更多
Root(大扎)
3楼-- · 2019-05-02 12:22

Is thunking now built natively into .NET by emitting IL code? If so, at what version of .NET did this become natively supported?

No IL in involved in the thunk, it happens by emitting native code -- a trampoline that rearranges arguments to meet .NET's calling convention, including the this pointer which is saved in case of closed delegates, and then performs a tail call to the .NET method itself.

Is implicit "thunking" supported in Mono as well?

This is called "reverse p/invoke", that should make it easy to look for in the Mono docs.

When the IL is emitted for the managed callbacks, what happens when the instance the thunk refers to is deleted?

When the delegate is garbage collected, memory used by the trampoline is also freed. So you need to keep the delegate alive as long as the native code has a pointer to the trampoline.

查看更多
登录 后发表回答