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一致

  1. 将Managed Function 转化为 Delegate
ONSESSIONREPLY^ pFunc = gcnew ONSESSIONREPLY(this, &YourClass::MemberFunction);
ONSESSIONREPLY^ pFunc = gcnew ONSESSIONREPLY(YourClass::StatiMemberFunction);
  1. 将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/33393690/passing-a-c-sharp-callback-function-into-managed-and-unmanaged-c-libraries

https://stackoverflow.com/questions/28982669/does-gchandle-alloc-allocate-memory

posted on 2023-08-06 15:55  norsd  阅读(2)  评论(0编辑  收藏  举报  来源

导航