Prev: How to know an object is being referenced by which object(s)?
Next: about code Access security(CAS)
From: Boris on 14 Apr 2010 20:11 Hello, There's an example in .Net docs where C# delegate is called by native code ( EnumWindows - http://msdn.microsoft.com/en-us/library/d186xcf0(v=VS.71).aspx ). The doc states: >>>PASTE>>>>>>> 4.Ensure that the garbage collector does not reclaim the delegate before the callback function completes its work. When you pass a delegate as a parameter, or pass a delegate contained as a field in a structure, it remains uncollected for the duration of the call. So, as is the case in the following enumeration example, the callback function completes its work before the call returns and requires no additional action by the managed caller. <<<PASTE<<<<<<<< - so, because garbage collection is disabled for duration of the call (EnumWindows) - everything is fine. The doc also states: >>>PASTE>>>>>>> If, however, the callback function can be invoked after the call returns, the managed caller must take steps to ensure that the delegate remains uncollected until the callback function finishes. For detailed information about preventing garbage collection, see Interop Marshaling with Platform Invoke. <<<PASTE<<<<<<<< I couldn't find any detailed description on how to handle this later case in the docs (even though it says "see Interop Marshaling with Platform Invoke". I have code that uses this very scenario and would like to know if my code (below) is safe in regards to garbage collection. My concern: garbage collector could move the delegate around, but native code would still use old address for callback. Code on managed side (C#) - error handling skipped for brevity: public class TheForm : System.Windows.Forms.Form { ... private SomeClass m_SomeClass; ... private void TheForm_Load(...) { ... m_SomeClass = new SomeClass(this); m_SomeClass.Start(); ... } ... } public class SomeClass { .... public delegate void MyDelegateCallback(String strText); public static MyDelegateCallback m_callback; private IntPtr m_hListener; private ArrayList cachedTextList; .... [System.Runtime.InteropServices.DllImport("SomeDll.dll", Charset=...Ansi)] public static extern IntPtr MyNative_CreateListener(MyDelegateCallback pCallback); .... public void MyCallbackFunc(String strText) { // Just add text to the list to be processed later m_cachedTextList.Add(strText); } .... public void Start() { m_callback = new MyDelegateCallback(MyCallbackFunc); m_hListener = MyNative_CreateListener(m_callback); } } Code on native side - in some DLL ( C ) - error handling skipped for brevity: typedef void ( __stdcall *PFUNCEVENT) (char *strText); DWORD WINAPI MyThreadProc( __in LPVOID pParameter ) { PFUNCEVENT pCallBack = (PFUNCEVENT) pParameter; Sleep(5000); pCallBack("some text"); return 0; } __declspec(dllimport) PVOID MyNative_CreateListener(PFUNCEVENT pCallBack) { DWORD threadId = 0; PDWORD pContext = malloc(sizeof(DWORD)); *pContext = 0; CreateThread(NULL,0,MyThreadProc,(LPVOID)pCallBack,0,&threadId); return (PVOID) context; }
From: Peter Duniho on 14 Apr 2010 21:23 Boris wrote: > [...] >>>> PASTE>>>>>>> > If, however, the callback function can be invoked after the call > returns, the managed caller must take steps to ensure that the delegate > remains uncollected until the callback function finishes. For detailed > information about preventing garbage collection, see Interop Marshaling > with Platform Invoke. > <<<PASTE<<<<<<<< > > I couldn't find any detailed description on how to handle this later > case in the docs (even though it says "see Interop Marshaling with > Platform Invoke". > I have code that uses this very scenario and would like to know if my > code (below) is safe in regards to garbage collection. My concern: > garbage collector could move the delegate around, but native code would > still use old address for callback. I'm not an expert, but my understanding is that the p/invoke layer wraps the managed delegate with its own function pointer. So the pointer that the unmanaged code gets isn't actually a pointer directly into your delegate instance. You should be able to accomplish the required safety simply by keeping your own managed reference to the delegate instance as long as the unmanaged code is holding on to the marshaled function pointer. Note that that's all that the code example on this page does: http://msdn.microsoft.com/en-us/library/7esfatk4(VS.71).aspx This article seems to agree with my understanding: http://msdn.microsoft.com/en-us/magazine/cc164193.aspx#S7 Pete
From: Boris on 18 Apr 2010 02:55 Thanks a lot Peter. This was very helpful. Boris
|
Pages: 1 Prev: How to know an object is being referenced by which object(s)? Next: about code Access security(CAS) |