2012-07-09 31 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