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)
How can I get the function pointer (long type) from delegate? (C# calls C/C++ dll and there's a callback function)
- Vista 64-bit Enterprise, Visual Studio 200832-bit C/C++ dll (I have changed the target platform to x86)I got a dll (SKQuoteLib.dll) and its doc.C/C++ dllint __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 OKbut there's no "haha"Ctrl + F5: normal, no exceptionF5: vshost32.exe error closing program, choose VS2008 as debug tooland 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 useVB: 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
- 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
- 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. 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.and it will callback later automatically
Right. There is no "later" in your code, your program terminates almost immediately after the call.
Hans Passant.- I found that I misunderstood something and I decided to repost it again as below:C/C++ dllint __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 callbackC#
// 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"); }
RESULTAttach Connection Status: 0EnterMonitor Status: 0I 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. - The "long" type in unmanaged C/C++ is the int type in C# code, 32-bits.
Hans Passant. 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?- 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
Hi Percy,
目前我也正在測試該DLL 的CALLBACK,請問你是否方便提供 SKQuoteLib_AttachConnectionCallBack 的用法程式碼,供我參考
謝謝// 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); }
Hi Percy,
謝謝!!


