locked
Delegate being collected even though I have a reference RRS feed

  • Question

  • I'm getting the 'When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.' advice from my program. Here is the code:

     

    • Edited by Freqy Thursday, December 23, 2010 10:34 PM
    Thursday, December 23, 2010 1:27 AM

Answers

  • [forehead smack]

    You may notice that part of this convoluted process I am passing callbacks via my delegates. It was these callbacks I was losing the reference to, NOT the callbacks highlighted each time the program crashed.

    The moral is that you must check not the delegate you've called at the time of the crash, but also the unmanaged code behind it.

    Hints from me would include switching your debugger to mixed mode and debugging from the unmanaged end if possible.


    Working in C++ reminds me that some things are almost as illogical as Microsoft
    • Marked as answer by Freqy Friday, January 28, 2011 4:48 AM
    Friday, January 28, 2011 4:48 AM

All replies

  • Hilarious. It's even put my paragraphs out of order. It actually IS as bad as MS Word.

    I daren't type below the code block again...

    As you can see there is clearly a reference to the delegate, and this object MUST still exist because it is within the code of recordF where the error usually occurs.

    using System;
    using System.Runtime.InteropServices;
    
    namespace StructuredLogViewer2
    {
      // Define the method signatures for functions we want to call on the DLLs we load.
      public delegate void OTLVInitialiseModuleDelegate( string extension, IntPtr callbacks );
      public delegate void OTLVResetHandlerDelegate();
      public delegate void OTLVHandleBufferDelegate( IntPtr data, UInt32 dataLength, Int32 addToDatabase, Int32 handleOnlyOne, IntPtr badData );
      public delegate void OTLVSetupRecordViewDelegate( IntPtr logRecordContext );
    
      // Opens a DLL using the CppDllLoader and tries to find the interface of a LogViewerDll.
      public class LogViewerDllLoader
      {
        // The delegate instances that will be linked to the DLL in question (if it works).
        private OTLVInitialiseModuleDelegate init;
        private OTLVResetHandlerDelegate reset;
        private OTLVHandleBufferDelegate buffer;
        private OTLVSetupRecordViewDelegate record;
    
        // The constructor accepts the (path) name of the DLL we are trying to wrap.
        public LogViewerDllLoader(string dllPath)
        {
          try
          {
            IntPtr someDLL = CppDllLoader.loadDLL(dllPath);
    
            IntPtr someFunc = CppDllLoader.GetProcAddress(someDLL, "OTLVInitialiseModule");
            init = (OTLVInitialiseModuleDelegate)Marshal.GetDelegateForFunctionPointer(someFunc, typeof(OTLVInitialiseModuleDelegate));
    
            someFunc = CppDllLoader.GetProcAddress(someDLL, "OTLVResetHandler");
            reset = (OTLVResetHandlerDelegate)Marshal.GetDelegateForFunctionPointer(someFunc, typeof(OTLVResetHandlerDelegate));
    
            someFunc = CppDllLoader.GetProcAddress(someDLL, "OTLVHandleBuffer");
            buffer = (OTLVHandleBufferDelegate)Marshal.GetDelegateForFunctionPointer(someFunc, typeof(OTLVHandleBufferDelegate));
    
            someFunc = CppDllLoader.GetProcAddress(someDLL, "OTLVSetupRecordView");
            record = (OTLVSetupRecordViewDelegate)Marshal.GetDelegateForFunctionPointer(someFunc, typeof(OTLVSetupRecordViewDelegate));
          }
          catch (Exception ex) { }
        }
    
    
        // And so now we can map the four functions in the dynamically loaded DLL to real functions on this class.
    
        // OTLVInitialiseModule
        public void initF(string extension, IntPtr callbacks)
        {
          init(extension, callbacks);
        }
    
        // OTLVHandleBuffer
        public void bufferF(IntPtr data, UInt32 dataLength, Int32 addToDatabase, Int32 handleOnlyOne, IntPtr badData)
        {
          buffer(data, dataLength, addToDatabase, handleOnlyOne, badData);
        }
    
        // OTLVSetupRecordView
        public void recordF(IntPtr logRecordContext)
        {
          record(logRecordContext);
        }
    
        // OTLVResetHandler
        public void resetF()
        {
          reset();
        }
      }
    }
    
    

    Just trying to get value-for-money for the $20,000 worth of your products I support...
    Thursday, December 23, 2010 1:43 AM
  •  

    Hi,

     

    Thank you for your question, we're doing research on this case. It might take some time before we get back to you.


    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, December 29, 2010 9:21 AM
  • Thanks, I am continuing investigation at this end to see if some corruption is being caused at the unmanaged end.
    Working in C++ reminds me that some things are almost as illogical as Microsoft
    Wednesday, January 5, 2011 4:05 AM
  • what does the comment below mean?  What is the calling convention for these unmanaged methods.  I am not sure but i dont think GetFunctionPointerForDelegate works on this call and if it did you would have to pass in the the "this" pointer as the first parameter.  Not sure if that is the issue just guessing based off the comment.

    EDIT

    I read the comment incorrectly :)

    And so now we can map the four functions in the dynamically loaded DLL to real functions on this class.
    
    
    Saturday, January 15, 2011 4:00 AM
  • The DLL has a C-style interface, so they are all explicitly defined __stdcall
    Working in C++ reminds me that some things are almost as illogical as Microsoft
    Thursday, January 20, 2011 10:57 PM
  • I am still showing this problem occcurring consistently, at the time where the delegate is called. Is there any progress on reproducing the problem?
    Working in C++ reminds me that some things are almost as illogical as Microsoft
    Thursday, January 27, 2011 4:37 AM
  • [forehead smack]

    You may notice that part of this convoluted process I am passing callbacks via my delegates. It was these callbacks I was losing the reference to, NOT the callbacks highlighted each time the program crashed.

    The moral is that you must check not the delegate you've called at the time of the crash, but also the unmanaged code behind it.

    Hints from me would include switching your debugger to mixed mode and debugging from the unmanaged end if possible.


    Working in C++ reminds me that some things are almost as illogical as Microsoft
    • Marked as answer by Freqy Friday, January 28, 2011 4:48 AM
    Friday, January 28, 2011 4:48 AM