C++/CLI Managed Function To Native Callback Function
一. 关键内核
System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate
此函数实现了Delegate转化为Native Function
二. 具体步骤
1. 创造和Native Function 一致的Delegate
Native Function:
typedef bool (*ONSESSRELY)(HANDLE_CONN, HANDLE_SESSION, long); //long 为 32bit
Managed Delegate:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool ONSESSIONREPLY(IntPtr hConnect, IntPtr hSession, eAbossFn fnId);// eAbossFn 是 enum:int
注意调用方式必须和Native Function一致
- 将Managed Function 转化为 Delegate
ONSESSIONREPLY^ pFunc = gcnew ONSESSIONREPLY(this, &YourClass::MemberFunction);
ONSESSIONREPLY^ pFunc = gcnew ONSESSIONREPLY(YourClass::StatiMemberFunction);
- 将Delegate转化为Native Function
GCHandle gch = GCHandle::Alloc(pFunc);// System::Runtime::InteropServices::GCHandleType::Pinned);
auto thunk = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(pFunc);
::Native_RegisterService(hSess.ToInt32(), thunk.ToPointer());
//Free gch, after Native used thunk
4.注意事项
关于Delegate实例,必须在其被Native调用前不能被GC回收。
有2中方法。
a.保存在类的结构中
b.保存在GCHandle中
一旦被GC回收后,Native 如果调用 thunk 将会访问未知内容
所以,你可以自己存储在类结构中,或者存储在 GCHandle中。
这两种方法都需要自己维护Delegate的生存周期。
注意: Delegate 使用 GCHandle::Alloc来保存Delegate时,不需要,也无法设置为 Pinned
因为尽管GCHadle::Alloc保存Delegate后,因为没有Pinned,其真实地址会被GCmove,但是函数GetFunctionPointerForDelegate在转换Delegate到Native Function时,在GC外部创建了一个“native thunk” ,这个 “native thunk”才是native 访问的地址, 当然 native thunk 内部会接着访问 managed delegate。
Chris Brumme wrote:
Along the same lines, managed Delegates can be marshaled to unmanaged code, where they are exposed as unmanaged function pointers. Calls on those pointers will perform an unmanaged to managed transition; a change in calling convention; entry into the correct AppDomain; and any necessary argument marshaling. Clearly the unmanaged function pointer must refer to a fixed address. It would be a disaster if the GC were relocating that! This leads many applications to create a pinning handle for the delegate. This is completely unnecessary. The unmanaged function pointer actually refers to a native code stub that we dynamically generate to perform the transition & marshaling. This stub exists in fixed memory outside of the GC heap.
https://stackoverflow.com/questions/28982669/does-gchandle-alloc-allocate-memory
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)