|
Comments and Discussions
|
|
 |
 |
Exactly what I wanted to know, thank you!
God Bless!
|
|
|
|
 |
Your sample is very helpful, thanks a lot.
But when I implemented it in my project, I encountered some problem.
The C++ dll I want to call is a network program which is used to send and receive data from web, and I want to call it in c#.
#include "stdafx.h"
class CSimpleHandler : public CThostFtdcTraderSpi
{
public:
CSimpleHandler(CThostFtdcTraderApi *pUserApi) : m_pUserApi(pUserApi)
{
}
~CSimpleHandler() {}
virtual void OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool
bIsLast)
{
printf("ErrorCode=[%d], ErrorMsg=[%s]\n",pRspInfo->ErrorID, pRspInfo->ErrorMsg);
};
}
int _tmain(int argc, _TCHAR* argv[])
{
CThostFtdcTraderApi *pUserApi = CThostFtdcTraderApi::CreateFtdcTraderApi();
CSimpleHandler sh(pUserApi);
CThostFtdcInputOrderField ord;
m_pUserApi->ReqOrderInsert(&ord, 1);
return 0;
}
The callback funtion is surpposed to be called in the OnRspOrderInsert function of CSimpleHandler class, so the respond could be passed to the C# program. But the function OnRspOrderInsert would not be executed if I call the ReqOrderInsert function in C#.The following is part of the code.
#include "stdafx.h"
static order_status_change_type _order_status_change;
class CSimpleHandler : public CThostFtdcTraderSpi
{
public:
CSimpleHandler(CThostFtdcTraderApi *pUserApi) : m_pUserApi(pUserApi)
{
}
~CSimpleHandler() {}
virtual void OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool
bIsLast)
{
printf("ErrorCode=[%d], ErrorMsg=[%s]\n",pRspInfo->ErrorID, pRspInfo->ErrorMsg);
_order_status_change(pRspInfo->ErrorMsg);
};
}
TESTLIB_API void __cdecl ReqOrderInsert(order_status_change_type order_status_change)
{
_order_status_change = order_status_change;
CThostFtdcTraderApi *pUserApi = CThostFtdcTraderApi::CreateFtdcTraderApi();
CSimpleHandler sh(pUserApi);
CThostFtdcInputOrderField ord;
m_pUserApi->ReqOrderInsert(&ord, 1);
}
I could send you my project including the source code if you need.
Very appreciate if you could reply.
|
|
|
|
 |
Hi,
This solution is for .NET 1.1 only. For .NET 2.0 and above use this to declare your delegate:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int Foobar(int foo);
Regards,
Jecho
|
|
|
|
 |
I tested your demo today on vs 2010, but it throw exception at
SetCallback( DelegateGenerator.CreateDelegate( callback ) );
the exception is
An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll
I noticed that in your demo, you already added the code:
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
public delegate void CallbackDelegate( int count );
and
[DllImport("TestLib.dll",CallingConvention=CallingConvention.Cdecl)]
public static extern void SetCallback( MulticastDelegate callback );
As you mention in before message, so how can I use it in vs2010?
Thanks.
|
|
|
|
 |
Hi,
The code works only for .NET 1.1. For .NET 2.0 and above use the following:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int Foobar(int foo);
Regards,
Jecho
|
|
|
|
 |
Do you mean?
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate void CallbackDelegate( int count );
I tested again,also throw exception of 'System.MissingMethodException' .
|
|
|
|
 |
Hi,
You do not need my solution for .NET 2.0 and above. All you have to do is to decorate your delegate with
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
and pass an instance of it to a native function. For example:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int Foobar(int foo);
static extern void NativeFunction(Foobar callback);
static void Test()
{
var method = new Foobar(FoobarCallbackMethod);
NativeFunction(method);
}
Regards,
Jecho
|
|
|
|
 |
Hi Jecho:
Thanks alot, it works.
Thanks
|
|
|
|
 |
Hi Jecho:
Sorry for bother you again.
I meet a problem in c call back in c#.
For example:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
internal delegate bool TMCC_ENUMSERVER_CALLBACK(ref tmServerInfo_t pEnum, IntPtr context);
Here TMCC_ENUMSERVER_CALLBACK is a callback delegate used in c method.
and the c method:
[DllImport("tmControlClient.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int TMCC_EnumServer([MarshalAs(UnmanagedType.FunctionPtr)] TMCC_ENUMSERVER_CALLBACK pCallBack, IntPtr context, bool bRegisterCallBack = false);
TMCC_EnumServer is used to register the callback function, the callback function will be called from the c dll in async mode.
Here is my c# code of calling the c function:
public static void enumCamera()
{
CameraServerList csl = new CameraServerList();
int ns = Marshal.SizeOf(csl);
IntPtr tp = Marshal.AllocHGlobal(ns);
Marshal.StructureToPtr(csl, tp, false);
var method = new TMCC_ENUMSERVER_CALLBACK(EnumServer);
int temp = tmControlClient.TMCC_EnumServer(method, tp, false);
return;
}
private static bool EnumServer(ref tmServerInfo_t pEnum, IntPtr contex)
{
return true;
}
enumCamera will register EnumServer as callback it works, and the C# main thread go on, and in async mode, the Enumserver function will be called by the new thread of c dll, but every time during calling EnumServer from c thread, the whole C# program will crash.
Should I do something special in this C dll call C# callback in async mode?
Thanks
|
|
|
|
 |
You must keep a reference to the "method" variable. If the variable is garbage collected the next call from native code will crash.
|
|
|
|
 |
I add two lines:
I the class add a private static member:
private static object methodStore;
And after set the callback:
store the method in the methodStoe:
methodStore = method;
But the program still crash.
How can I fix it?
Thanks
|
|
|
|
 |
Hi,
If a reference to the callback is kept while it's being used then the problem is somewhere else.
Regards,
Jecho
|
|
|
|
 |
I added the code fix as the author suggested and program still crashes. The crash happens on the
MulticastDelegate del = DelegateGenerator.CreateDelegate(callback); line of code and the exception is Method 'System.Reflection.Emit.TypeBuilder.Exit' not found.
public static GCHandle SetCallback(CallbackDelegate callback)
{
MulticastDelegate del = DelegateGenerator.CreateDelegate(callback);
GCHandle handle = GCHandle.Alloc(del, GCHandleType.Pinned);
SetCallback(del);
return handle;
Its apparent the code sucks
|
|
|
|
 |
Hi,
The code works only for .NET 1.1. For .NET 2.0 and above use the following:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int Foobar(int foo);
As I said in this comment: Link[^]
Regards,
Jecho
|
|
|
|
 |
no use even reading this article or downling the source or demos
the executable file blow up when ran
Place Jecho Jekoov on the avoid list
|
|
|
|
 |
You saved my neck, mate
|
|
|
|
 |
This was the final piece of the puzzle for me.. excellent work! I'm also particularly impressed that you are keeping abreast of current changes and making sure folks know the answers.. well done!
|
|
|
|
 |
Hi everyone,
The posted code has a serious flaw related to garbage collection and may lead to NullReferenceException .
Please read about this problem here and the solution here.
Regards,
Jecho
|
|
|
|
 |
Hi everyone,
This article is outdated. The code is designed for .NET 1.1 only. Please use the following code for .NET 2.0 and above:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int Foobar(int foo); Regards,
Jecho
|
|
|
|
 |
[UnmanagedFunctionPointer] attribute also prevents the delegate from been collected by the GC
Dios existe pero duerme...
Sus pesadillas son nuestra existencia.
(Ernesto Sabato)
|
|
|
|
 |
but you still got my five, good article!
Dios existe pero duerme...
Sus pesadillas son nuestra existencia.
(Ernesto Sabato)
|
|
|
|
 |
Hi there.
If you need to specify the calling convention for a delegate in .NET 2.0 and above, you can simply use the UnmanagedFunctionPointerAttribute attribute on your delegate.
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int Foobar(int foo);
|
|
|
|
 |
I still have run time error:
An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll
Additional information: Attempted to access a missing member
So many changes were offered that I am completely lost.
Could you please publish revised code again?
|
|
|
|
 |
Hi,
Please, read this[^] comment.
Regards,
Jecho
|
|
|
|
 |
Testing generated delegate...
Unhandled Exception: System.MissingMethodException: Method 'System.Reflection.Emit.TypeBuilder.Enter' not found.
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo cultur
e, String[] namedParams)
at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args)
at App.Utils.Reflector.InvokeMember(Type type, String name, Object instance, BindingFlags flags, Object[] parameters) in D:\JXDW\QCA\Other\App\Utils\Reflector.cs:line 66
at App.Utils.Reflector.InvokeMethod(Type type, String name, Object instance, Object[] parameters) in D:\JXDW\QCA\Other\App\Utils\Reflector.cs:line 36
at App.Runtime.InteropServices.DelegateGenerator.Generate(MethodInfo method, String typeName, CallingConvention callingConvention) in D:\JXDW\QCA\Other\App\Runtime\InteropServic
es\DelegateGenerator.cs:line 157
at App.Runtime.InteropServices.DelegateGenerator.CreateDelegate(Object obj, MethodInfo method, CallingConvention callingConvention) in D:\JXDW\QCA\Other\App\Runtime\InteropServi
ces\DelegateGenerator.cs:line 462
at App.Runtime.InteropServices.DelegateGenerator.CreateDelegate(Delegate del, CallingConvention callingConvention) in D:\JXDW\QCA\Other\App\Runtime\InteropServices\DelegateGener
ator.cs:line 424
at App.Runtime.InteropServices.DelegateGenerator.CreateDelegate(Delegate del) in D:\JXDW\QCA\Other\App\Runtime\InteropServices\DelegateGenerator.cs:line 406
at DelegateGeneratorDemo.DelegateGeneratorDemo.SetCallback(CallbackDelegate callback) in D:\JXDW\QCA\Other\AppDemo\DelegateGeneratorDemo\DelegateGeneratorDemo.cs:line 23
at DelegateGeneratorDemo.DelegateGeneratorDemo.Main(String[] args) in D:\JXDW\QCA\Other\AppDemo\DelegateGeneratorDemo\DelegateGeneratorDemo.cs:line 51
Unhandled Exception: System.MissingMethodException: Method 'System.Reflection.Emit.TypeBuilder.Exit' not found.
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo cultur
e, String[] namedParams)
at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args)
at App.Utils.Reflector.InvokeMember(Type type, String name, Object instance, BindingFlags flags, Object[] parameters) in D:\JXDW\QCA\Other\App\Utils\Reflector.cs:line 66
at App.Utils.Reflector.InvokeMethod(Type type, String name, Object instance, Object[] parameters) in D:\JXDW\QCA\Other\App\Utils\Reflector.cs:line 36
at App.Runtime.InteropServices.DelegateGenerator.Generate(MethodInfo method, String typeName, CallingConvention callingConvention) in D:\JXDW\QCA\Other\App\Runtime\InteropServic
es\DelegateGenerator.cs:line 238
at App.Runtime.InteropServices.DelegateGenerator.CreateDelegate(Object obj, MethodInfo method, CallingConvention callingConvention) in D:\JXDW\QCA\Other\App\Runtime\InteropServi
ces\DelegateGenerator.cs:line 462
at App.Runtime.InteropServices.DelegateGenerator.CreateDelegate(Delegate del, CallingConvention callingConvention) in D:\JXDW\QCA\Other\App\Runtime\InteropServices\DelegateGener
ator.cs:line 424
at App.Runtime.InteropServices.DelegateGenerator.CreateDelegate(Delegate del) in D:\JXDW\QCA\Other\App\Runtime\InteropServices\DelegateGenerator.cs:line 406
at DelegateGeneratorDemo.DelegateGeneratorDemo.SetCallback(CallbackDelegate callback) in D:\JXDW\QCA\Other\AppDemo\DelegateGeneratorDemo\DelegateGeneratorDemo.cs:line 23
at DelegateGeneratorDemo.DelegateGeneratorDemo.Main(String[] args) in D:\JXDW\QCA\Other\AppDemo\DelegateGeneratorDemo\DelegateGeneratorDemo.cs:line 51
There is no 'System.Reflection.Emit.TypeBuilder.Enter' method in .NET2.0,3.0,3.5.
|
|
|
|
 |
Use [DllImport(CallingConvention=CallingConvention.Cdecl)] .
|
|
|
|
 |
I use VB 2005.net and got no 'System.Reflection.Emit.TypeBuilder.Exit'.What can I do?
ewre
|
|
|
|
 |
Use
[DllImport(CallingConvention=CallingConvention.Cdecl)] on external methods and
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] on delegates.
|
|
|
|
 |
Use [DllImport("MyLib.dll", CallingConvention = CallingConvention.Cdecl)] in .NET 2.0 and above.
Important: Read this comment[^] before you use the code.
|
|
|
|
 |
How can implement a C function like
typedef void ( CALLBACK* DOWNLOADING )(ULONG,LPARAM,LPBOOL);
thanks
Khayralla
|
|
|
|
 |
Use[DllImport("MyLib.dll", CallingConvention = CallingConvention.Cdecl)] in .NET 2.0.
|
|
|
|
 |
Is it possible to have multiple Callbacks in C++?
I can't figure out how to create a second callback function based on
typedef void (__cdecl *func_type)(int count);
A second tydef declaration of *func_type would produce an error.
Thanks
|
|
|
|
 |
You cannot declare two types with the same name.
|
|
|
|
 |
unless i misunderstood ur example... (and btw, great idea and coding).. but you already have the answer before coding this...
if the delegate expects to be called as a standard __stdcall.. then all u have to do it preface ur callback pointer in the DLL with...
(__stdcall)...
so for example.. all my exported func's in the DLL have:
extern "C" __declspec( dllexport ) int myFunc(...);
it works like a charm. u can have different calling conventions in the same DLL....
here are the required code parts...
//////////////////////////////////////// win32 DLL code....
// .h file
#define MXOBJECT_API extern "C" __declspec( dllexport )
typedef void (__stdcall *w_CallBack) (int status);
// .cpp file
w_CallBack dnQueryCallBack; // my .Net callback delegate
MXOBJECT_API bool SetQueryHandler(w_CallBack dnDelegatePtr) {
// dnQueryCallBack now points to the .net delegate in Managed Code
dnQueryCallBack = dnDelegatePtr;
return true;
}
// test func to have .Net call and tell it to fire the .Net delegate
MXOBJECT_API int CallQueryHandler(int data) {
dnQueryCallBack(data);
return -data; // just to check something
}
//////////////////////////////////////// .Net bridge to DLL code...
class MxObjectAPI
{
[DllImport("MxObject.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetQueryHandler(MulticastDelegate d);
[DllImport("MxObject.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int CallQueryHandler(int data);
}
public delegate int QueryDelegate(int cmdID);
public class QueryCallBack
{
public int OnQuery(int cmdID)
{
return cmdID;
}
}
public class MxBridge
{
QueryCallBack cb = null;
MulticastDelegate qd = null;
public MxBridge()
{
cb = new QueryCallBack();
qd = new QueryDelegate(cb.OnQuery);
// call the dll and set the function callback pointer
bool rVal = MxObjectAPI.SetQueryHandler(qd);
if (rVal == false)
{
throw new Exception("MxBridge: could not set function callback.");
}
}
public int CallQueryHandler(int cmdID)
{
return MxObjectAPI.CallQueryHandler(cmdID);
}
}
//////////////////////////////////////// .Net main.cs code...... an example call to dll to make it call .net
MxBridge mx = new MxBridge();
for (int i = 0; i < 1000; ++i)
{
int rval = mx.CallQueryHandler(i * 5);
}
(ps.. but i learned somethings from ur Reflection example - thx )
|
|
|
|
 |
I am trying to use this example, but I cannot generate the DLL correctly. I get the BadImageFormatException. I am using the Express edition of C# and VC. I have tried the suggestion here http://msdn.microsoft.com/en-us/library/k7137bfe(VS.80).aspx
but still cannot get the dll created correctly. I can get call user32.dll using this.
Michael
|
|
|
|
 |
jsfunfun's sample works perfectly for me in VS2010
|
|
|
|
 |
Yes, I know that .NET 2.0 has fixed the problem.
I need to restrict my code to .NET 1.0 because I will eventually have to build for Pocket PC 2002 (not supported in VS2005). But I like the intellisense and other features in VS2005.
So if is possible, with minimal changes, to get this code to work in VS2005?
If not, no biggie - I'll just have to use VS2003.
Thanks,
Paul
|
|
|
|
 |
Hi Paul,
I have no time to research if the code as it is works in .NET 2.0. I would suggest you to use the .NET 2.0 attributes and switch to this article's solution when you want to build a release version.
Regards,
Jecho
|
|
|
|
 |
The code posted in the original article is incorrect and will easily lead to "NullReferenceException" after a number of invocations on the callback from unmanaged code.
Please read about this problem here and the solution here.
|
|
|
|
 |
Dear Sir,
This artical is very useful for me.
I try to write a form program to receive the callback function.
But I get an exception on my program.
My code likes below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using App.Runtime.InteropServices;
namespace TestCallBack
{
public partial class Form1 : Form
{
///
[DllImport("TestLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetCallback(MulticastDelegate callback);
///
[DllImport("TestLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void InvokeCallback();
///
/// Callback delegate.
///
public delegate void CallbackDelegate(int count);
///
/// Sets specified callback method.
///
///
public static void SetCallback(CallbackDelegate callback)
{
//Console.WriteLine("Create Callback...");
try
{
SetCallback(DelegateGenerator.CreateDelegate(callback));
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Initial all
initial_UI_codition();
CallbackDelegate del = new CallbackDelegate(Callback);
SetCallback(del);
}
private static void Callback(int count)
{
Console.WriteLine("Callback invoked for " + count + " time");
}
}
I run step by step to debug, it will get an exception on below code.
SetCallback(DelegateGenerator.CreateDelegate(callback));
The exception code is 0x80131512.
It is MissingMemberException.
Is this method is wrong on the form class?
Do I need change anything for this issue?
Thanks.
|
|
|
|
 |
Are you using .NET 1.1 or .NET 2.0? If you use .NET 2.0 then use [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]. See the following comment:
http://www.codeproject.com/dotnet/Cdecl_CSharp_VB.asp?msg=1904825#xx1904825xx
|
|
|
|
 |
Yes, I use the .Net 2.0.
Thanks for your great help.
|
|
|
|
 |
Jecho, thank you very much for this amazing code.
I'm still working with .net 1.1 and after looking the proposed solutions on the web (involving disassembly, patching and reassembly) I was already considering writing a C wrapper just to fix the calling convention. Fortunately I found your article before. It's working like a charm.
Cheers!
Sergio
An interesting form of object-oriented programming:
You suggest a novel algorithm, and watch as the rest of your team objects!
|
|
|
|
 |
Sergio,
I'm also still using .NET 1.1 so cheers to you as well
|
|
|
|
 |
Hi,
It is very nice artile!
I import the demo to VS2005 and the folllowing exception occur at runtime:
"Method 'System.Reflection.Emit.TypeBuilder.Enter' not found."
and
"Method 'System.Reflection.Emit.TypeBuilder.Exit' not found."
...
Who can tell me how to solve it ?
Thank you !
Alger
|
|
|
|
|
 |
I am facing same problem. I tried with VS2008 and dotNet3.5
I think your given link is not perfect. Its the link of this project.
Would you recheck please.
Thanks.
|
|
|
|
 |
you are right! but..
I don't remember anything about it! I'm sorry..
|
|
|
|
 |
Hi,
Please use[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] in .NET 2.0 and above. This problem has been solved since .NET 2.0. The code is designed for .NET 1.1. only.
|
|
|
|
 |
I have the same error. I tried the solution of new attribute with .net 2.0, but still have the same problem.
If somecan provide suggestion will be helpful
thanks
|
|
|
|
|
 |
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
First Posted | 13 Sep 2005 |
Views | 203,287 |
Bookmarked | 61 times |
|
|