Visual C# Developer Center > Visual C# Forums > Visual C# General > How can I get the function pointer (long type) from delegate? (C# calls C/C++ dll and there's a callback function)
Ask a questionAsk a question
 

AnswerHow can I get the function pointer (long type) from delegate? (C# calls C/C++ dll and there's a callback function)

  • Tuesday, October 06, 2009 3:35 AMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Vista 64-bit Enterprise, Visual Studio 2008
    32-bit C/C++ dll (I have changed the target platform to x86)


    I got a dll (SKQuoteLib.dll) and its doc.

    C/C++ dll
    int __stdcall SKQuoteLib_AttachConnectionCallBack([in]long lCallBack)

    the call back function should match:
    typedef void ( __stdcall* FOnNotifyConnection)( int nKind, int nCode)


    I want to use it in C#.

    C#
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void FOnNotifyConnection(int nKind, int nCode);
    
    [DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
    extern static int SKQuoteLib_AttachConnectionCallBack( [MarshalAs(UnmanagedType.FunctionPtr)] FOnNotifyConnection Delegate_AttachConnection );
    // something I tried
    //extern static int SKQuoteLib_AttachConnectionCallBack(int lCallBack);
    //extern static int SKQuoteLib_AttachConnectionCallBack(FOnNotifyConnection Delegate_AttachConnection);
    //extern static int SKQuoteLib_AttachConnectionCallBack(Int32 lCallBack);
    
    static void Main(string[] args)
    {
        int temp = -1;
        FOnNotifyConnection Delegate_AttachConnection = new FOnNotifyConnection(CBFunc_AttachConnection);
        temp = SKQuoteLib_AttachConnectionCallBack(Delegate_AttachConnection);
        Console.WriteLine("Attach Connection Status: {0}", temp);
    }
    
    public static void CBFunc_AttachConnection(int nKind, int nCode)
    {
        Console.WriteLine("haha");
    }
    

    Result
    "Attach Connection Status: 0"
    which means OK
    but there's no "haha"

    Ctrl + F5: normal, no exception
    F5: vshost32.exe error closing program, choose VS2008 as debug tool
          and there's a message about "Cannot append to the process which has no response."
          (I use VS2008 CHT, so I don't know the original words. I just tried to translate it to ENG, may use the wrong word...)
          so that I can't see what exception occurred.

    PS.
    There are VB and VC++ example codes for the dll; they use
    VB: SKQuoteLib_AttachConnectionCallBack( AddressOf FUNCNAME )
    VC++: SKQuoteLib_AttachConnectionCallBack( (long) FUNCNAME )

    I know there's no function pointer in C#, only delegate.
    Is there any way to make SKQuoteLib_AttachConnectionCallBack callback properly?
    It just can take the "long" type of C/C++.

    Thanks for responding and bearing with my poor English.

    • Changed TypenobugzMVP, ModeratorWednesday, October 07, 2009 12:51 AMrequires vendor support
    • Changed TypePercy Lin Wednesday, October 07, 2009 7:44 AM
    • Edited byPercy Lin Tuesday, October 06, 2009 11:05 AM
    •  

Answers

  • Wednesday, October 07, 2009 7:42 AMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Thanks for Hans Passant's reminding, I found this: 
    and create a C# windows form project.

    I used Form1_Load() as Main() in the console program and it works just fine!
    ----------------------------------------------------------------------------------------------------------------------------------
    extern static int SKQuoteLib_AttachConnectionCallBack( 
        [MarshalAs(UnmanagedType.FunctionPtr)] FOnNotifyConnection Delegate_AttachConnection );
    ----------------------------------------------------------------------------------------------------------------------------------
    SKQuoteLib_AttachConnectionCallBack(Delegate_AttachConnection);
    ----------------------------------------------------------------------------------------------------------------------------------

    The problem might be something about thread.
    Anyway, I can go further now!!

    BTW, is it right to turn String to LPTStr for TCHAR* like this?

    // int __stdcall SKQuoteLib_RequestTicks( [in,out]short* psPageNo, [in]TCHAR* pStockNo)
    [DllImport("SKQuoteLib.dll")]
    extern static int SKQuoteLib_RequestTicks(
        [In, Out] short psPageNo,
        [MarshalAs(UnmanagedType.LPTStr)] String pStockNo);
    

    Thanks again!
    • Marked As Answer byPercy Lin Wednesday, October 07, 2009 7:44 AM
    •  

All Replies

  • Tuesday, October 06, 2009 4:15 AMnobugzMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    There is a mistake in your code, you assign the delegate instance to a local variable.  That's not good enough to keep the instance alive.  The garbage collector will eventually collect it, your code will crash afterwards.  Store it in a class member or static variable.

    But that's not your problem yet.  Looks to me that you've only set the callback but haven't done anything with the API yet that would make it use the callback.  Callbacks don't just stop happening, you code is otherwise correct.  Contact the library vendor for support.

    Hans Passant.
  • Tuesday, October 06, 2009 4:43 AMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    There is a mistake in your code, you assign the delegate instance to a local variable.  That's not good enough to keep the instance alive.  The garbage collector will eventually collect it, your code will crash afterwards.  Store it in a class member or static variable.
    Thanks for reminding, I've change it to
    -------------------------------------------------------------------------------------------------------------------------------------------------  
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void FOnNotifyConnection(int nKind, int nCode);
    
    static FOnNotifyConnection Delegate_AttachConnection = new FOnNotifyConnection(CBFunc_AttachConnection);
    
    -------------------------------------------------------------------------------------------------------------------------------------------------
    the situation remains the same though

    But that's not your problem yet. Looks to me that you've only set the callback but haven't done anything with the API yet that would make it use the callback. Callbacks don't just stop happening, you code is otherwise correct. Contact the library vendor for support.
    Just call SKQuoteLib_AttachConnectionCallBack and it will callback later automatically.
    The VB example code works fine so that I knew this from executing the VB program.

    I've contacted the library vendor, the futures specialist responded that they are researching it.
    (This API is for receiving quotation of futures or stocks.)
    I just try to solve it at the same time.
  • Tuesday, October 06, 2009 5:23 AMnobugzMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    and it will callback later automatically
    Right.   There is no "later" in your code, your program terminates almost immediately after the call.
    Hans Passant.
  • Tuesday, October 06, 2009 5:23 PMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    I found that I misunderstood something and I decided to repost it again as below:


    C/C++ dll

    int __stdcall SKQuoteLib_AttachConnectionCallBack([in]long lCallBack)
        the call back function should match:
        typedef void ( __stdcall* FOnNotifyConnection)( int nKind, int nCode)

    int __stdcall SKQuoteLib_EnterMonitor()
        it will make SKQuoteLib_AttachConnectionCallBack to callback


    C#

    // delegate for AttachConnectionCallBack
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void FOnNotifyConnection(int nKind, int nCode);
    
    static FOnNotifyConnection Delegate_AttachConnection = new FOnNotifyConnection(CBFunc_AttachConnection);        
    
    // int __stdcall SKQuoteLib_AttachConnectionCallBack([in]long lCallBack)
    [DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
    extern static int SKQuoteLib_AttachConnectionCallBack( [MarshalAs(UnmanagedType.FunctionPtr)] FOnNotifyConnection Delegate_AttachConnection );
    // something I tried
    //extern static int SKQuoteLib_AttachConnectionCallBack(int lCallBack);
    //extern static int SKQuoteLib_AttachConnectionCallBack(FOnNotifyConnection Delegate_AttachConnection);
    //extern static int SKQuoteLib_AttachConnectionCallBack(Int32 lCallBack);
    
    // int __stdcall SKQuoteLib_EnterMonitor()
    [DllImport("SKQuoteLib.dll")]
    extern static int SKQuoteLib_EnterMonitor();
    
    

    static void Main(string[] args)
    {
        // Attach Connection
        int temp = -1;
        temp = SKQuoteLib_AttachConnectionCallBack(Delegate_AttachConnection);
        Console.WriteLine("Attach Connection Status: {0}", temp);
    
        // Enter Monitor (Attach Connection to callback)
        temp = -1;
        temp = SKQuoteLib_EnterMonitor();
        Console.WriteLine("EnterMonitor Status: {0}", temp);
    }
    

    public static void CBFunc_AttachConnection(int nKind, int nCode)
    {
        Console.WriteLine("haha");
    }
    

    RESULT
    Attach Connection Status: 0
    EnterMonitor Status: 0

    I compiled it (press F5) with VS2008 at Windows XP Professional 32-bit in my VisualBox 3.0.6 virtual machine
    (The original platform is Vista Enterprise 64-bit)

    When the program terminates, it throws an error message:
    "Memory "0x00000004" referenced by Command "0x04631855". This Memory cannot be read."
    (It's a roughly translation from CHT to ENG.)


    The API only accept "long" type as its parameter.
    How can I get a proper one from delegate or something to make the callback occurred correctly?
    (which means "haha" in my result)

    Thanks for responding and bearing with my poor English.
  • Tuesday, October 06, 2009 5:55 PMnobugzMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    The "long" type in unmanaged C/C++ is the int type in C# code, 32-bits.
    Hans Passant.
  • Wednesday, October 07, 2009 12:40 AMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    The "long" type in unmanaged C/C++ is the int type in C# code, 32-bits.
    Yes, and I've tried something like this:

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void FOnNotifyConnection(int nKind, int nCode);
    
    static FOnNotifyConnection Delegate_AttachConnection = new FOnNotifyConnection(CBFunc_AttachConnection);
            
    [DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
    extern static int SKQuoteLib_AttachConnectionCallBack(int lCallBack);
    
    static void Main(string[] args)
    {
        int temp = -1;
        IntPtr p = Marshal.GetFunctionPointerForDelegate(Delegate_AttachConnection);
        temp = SKQuoteLib_AttachConnectionCallBack(p.ToInt32());
        Console.WriteLine("Attach Connection Status: {0}", temp);
    }
    

    and the situation is the same.
    Is there any other ways?
  • Wednesday, October 07, 2009 7:42 AMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Thanks for Hans Passant's reminding, I found this: 
    and create a C# windows form project.

    I used Form1_Load() as Main() in the console program and it works just fine!
    ----------------------------------------------------------------------------------------------------------------------------------
    extern static int SKQuoteLib_AttachConnectionCallBack( 
        [MarshalAs(UnmanagedType.FunctionPtr)] FOnNotifyConnection Delegate_AttachConnection );
    ----------------------------------------------------------------------------------------------------------------------------------
    SKQuoteLib_AttachConnectionCallBack(Delegate_AttachConnection);
    ----------------------------------------------------------------------------------------------------------------------------------

    The problem might be something about thread.
    Anyway, I can go further now!!

    BTW, is it right to turn String to LPTStr for TCHAR* like this?

    // int __stdcall SKQuoteLib_RequestTicks( [in,out]short* psPageNo, [in]TCHAR* pStockNo)
    [DllImport("SKQuoteLib.dll")]
    extern static int SKQuoteLib_RequestTicks(
        [In, Out] short psPageNo,
        [MarshalAs(UnmanagedType.LPTStr)] String pStockNo);
    

    Thanks again!
    • Marked As Answer byPercy Lin Wednesday, October 07, 2009 7:44 AM
    •  
  • Friday, October 30, 2009 6:24 AMkeith-- Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Percy,

    目前我也正在測試該DLL 的CALLBACK,請問你是否方便提供 SKQuoteLib_AttachConnectionCallBack 的用法程式碼,供我參考
    謝謝

  • Sunday, November 01, 2009 2:32 PMPercy Lin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    // 1.0.向報價函式庫註冊接收連線狀態的 Call back 函式位址
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void FOnNotifyConnection(Int32 nKind, Int32 nCode);
    // typedef void ( __stdcall* FOnNotifyConnection)( int nKind, int nCode )
    static FOnNotifyConnection Delegate_AttachConnection = new FOnNotifyConnection(CBFunc_AttachConnection);
    
    [DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
    extern static int SKQuoteLib_AttachConnectionCallBack(FOnNotifyConnection Delegate_AttachConnection);
    // int __stdcall SKQuoteLib_AttachConnectionCallBack([in]long lCallBack)
    
    private void Form1_Load(object sender, EventArgs e)
    {
        temp = -1;
        // 1.0.向報價函式庫註冊接收連線狀態的 Call back 函式位址
        temp = SKQuoteLib_AttachConnectionCallBack(Delegate_AttachConnection);
        Console.WriteLine("Attach Connection Status: {0}", temp);
    }
    
    // 1.0
    public static void CBFunc_AttachConnection(int nKind, int nCode)
    {
        Console.WriteLine("[Connection] Kind: {0}, Code: {1}", nKind, nCode);
    }
    
  • Wednesday, November 04, 2009 3:18 AMkeith-- Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Percy,
    謝謝!!