2012-07-09 28 views
8

我需要将托管回调传递给非托管TCP接收器。由于它的一个线程需要在应用程序的整个生命周期中存在,我需要阻止它被垃圾收集。我已经阅读过,固定函数指针并不是必需的,GCHandle.Alloc将完成防止垃圾收集的工作。固定一个函数指针

但这是给定的?我看到承载此代码的AppPool在访问冲突时崩溃。为什么我不应该怀疑因为函数指针被垃圾收集而发生此错误的事实?

这个post支持这个事实。

更新: 这似乎大大减少了崩溃。这种方法有问题吗?

typedef void (__cdecl *ProcMessageFunc)(void* param, void* paramBuf, ULONG bufSize); 
FuncDelegate^ fp = gcnew MessageFuncDelegate(this, &Handler); 
pin_ptr<MessageFuncDelegate^> pinnedFunctionPointer = &fp; 
ret = Receiver ((ProcMessageFunc)pinnedFunctionPointer); 
+3

将委托对象存储在一个静态变量中就足够了。由于其他原因,原生代码可能会因访问违规而爆炸。 – 2012-07-09 18:08:15

+0

我已经完成了。我倾向于怀疑垃圾回收是原因的原因是访问违规发生的不正常。更重要的是崩溃转储中的调用堆栈,我可以看到本机dll,随后是clr.dll,然后是堆栈顶部的kernel32.dll。这个顺序是一致的。 – Krishter 2012-07-10 02:28:49

回答

8

我做的正是你建议做什么 - GCHandle.Alloc的代表,但没有钉扎 - 并没有对许多不同的平台和.NET版本2.0中广泛使用的任何问题 - 4.东西像:

DelegateHandle = GCHandle.Alloc(xlDelegate); 
FunctionPointer = Marshal.GetFunctionPointerForDelegate(xlDelegate); 

FunctionPointer然后传递给本机代码,DelegateHandle保存后的清理工作。

这似乎是最好的参考:http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.80).aspx

这篇文章中没有任何内容指出与此参考相矛盾 - 您确实需要保护垃圾收集代理,只是不需要锁定

+0

地址固定的函数不是必需的,因为与堆对象不同,它们存在于常量位置?如果一个函数没有被任命为btw,那么它的地址是什么? – Dai 2012-07-09 19:47:16

+2

我认为对GetFunctionPointerForDelegate的调用会构建一个具有固定入口点的编组存根,但是如果委托被移动,存根仍然会知道如何调用它。所以导出的函数指针不是直接导出委托对象的地址(不像固定的数组或结构成员)。记住导出的“本地”功能也必须实现本地 - >管理转换。 – Govert 2012-07-09 19:50:35

+0

这正是我所做的。不幸的是,访问违规仍然发生。让我这样说吧。我怎样才能完全确定这不是访问违规的原因? – Krishter 2012-07-10 02:33:01