none
Trouble calling a function using Marshal::GetFunctionPointerForDelegate RRS feed

  • Question

  • I'm not sure if this is the right forum for this question, but here we go:

    I have a file with mixed managed and unmanaged C++. This is necessary because I'm using an API that is entirely unmanaged C++, and my main tool is in C#. I'm running into an issue with a function that needs to take a function pointer as an argument.

    I tried creating a delegate, then marshalling the delegate to a function pointer, but when I set breakpoints in the callback function, they never get hit, so I don't think this is working exactly like it should.

    Here's the code I have:

    // delegate to call the EnumCallBack funtion  
    delegate int EnumCallbackDelegate();  
     
    ...  
    // create a pointer to the delegate  
    EnumCallbackDelegate ^callbackDelegate = gcnew EnumCallbackDelegate(this, &myNamespace::myClass::EnumCallBack);  
     
    IntPtr pDelegate = Marshal::GetFunctionPointerForDelegate(callbackDelegate);  
    void *fp = pDelegate.ToPointer();  
     
    // call the function  
    UnmanagedFunction(fp);  
     
    // free the pointer used for the EnumCallbackDelegate  
    Marshal::FreeHGlobal(pDelegate); 

    Can you guys see anything wrong with this code? If a move the EnumCallBack function to a file containing only unmanaged code, I can just use a regular unmanaged function pointer and it works just fine, but I'd like to keep everything in this one file if I can.

    Thanks for your help :)
    Friday, October 31, 2008 3:16 PM

Answers

  • Marshal::GetFunctionPointerForDelegate() returns a pointer to code, not to data.  No need to release it, you can't release code.  Or to store it in a member, the garbage collector won't touch it.  Nor do you need to use the function, the CLR does it automatically.

    Getting the breakpoint is pretty important to get ahead.  Contact the company that sold you the license to use the DLL and ask for debugging symbols.

    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, November 6, 2008 3:11 PM
    Friday, October 31, 2008 8:59 PM
    Moderator

All replies

  • The FreeHGlobal() call is not correct, just remove it.  You must store the delegate instance (callbackDelegate) in a class member whose lifetime is at least as long as the need for the callback.   It looks like you used a local variable, as soon as it goes out of scope, the garbage collector will release it on the next sweep.

    However, your code should bomb when the unmanaged code calls the delegate target.  Why doesn't it?  What is actually being called?  Find out with the debugger.

    Hans Passant.
    Friday, October 31, 2008 5:24 PM
    Moderator
  • Okay, I will do this and let you know how it goes.


    I was under the inpression that whenever you marshalled a managed type to an unmanaged type that you had to free the memory used for the IntPtr.

    For example:

    virtual void Connect(String ^id)  
    {  
        // allocate a pointer to hold the id  
        IntPtr pId = Marshal::StringToHGlobalAnsi(id);  
     
        // connect to the target, and store the target for future use  
        mTarget = ConnectToConsole(static_cast<const char*>(pId.ToPointer()));  
     
        // free the pointer holding the id  
        Marshal::FreeHGlobal(pId);  

    Is that not a correct assumption?
    Friday, October 31, 2008 5:58 PM
  • Ok so I created a member variable and used it as follows:

    EnumCallbackDelegate ^mCallbackDelegate;     
        
    ...     
        
    mCallbackDelegate = gcnew EnumCallbackDelegate(this, &myNamespace::myClass::EnumCallBack);     
        
    ...     
        
    IntPtr pDelegate = Marshal::GetFunctionPointerForDelegate(mCallbackDelegate);     
    UnmanagedFunction(pDelegate.ToPointer());    
     

    The problem is that the Unmanaged function is in a .lib or a .dll and there's no source code available when I try to step in. The function takes a function pointer an as argument, and it iterates on some group, calling the function passed in for each item in the group.

    Does the IntPtr need to be a member variable as well?
    Friday, October 31, 2008 6:17 PM
  • Marshal::GetFunctionPointerForDelegate() returns a pointer to code, not to data.  No need to release it, you can't release code.  Or to store it in a member, the garbage collector won't touch it.  Nor do you need to use the function, the CLR does it automatically.

    Getting the breakpoint is pretty important to get ahead.  Contact the company that sold you the license to use the DLL and ask for debugging symbols.

    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, November 6, 2008 3:11 PM
    Friday, October 31, 2008 8:59 PM
    Moderator