我现在需要调用一个设备的sdk,里面有个函数用了回调函数,我查了些资料,也用了委托,可能我写错了,
不知道如何才能取得函数返回的数据。
函数如下:
int __stdcall tltmStartReadingItems(HANDLE hHandle, unsigned int uiFieldsMask, BOOL boSetEAS, 
void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmRawItem *myRawItem, void *pParam),
 void (__stdcall *lpfnCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmItem *myItem, void *pParam), void *pParam)哪位大哥指点一下小弟,谢谢!

解决方案 »

  1.   

    回调函数用.NET中的委托处理
    比如SDK中有个查找所有窗口的函数:
    [DllImport("user32")]
    private static extern bool EnumWindows(DelegateEnumWindow ew, int lParam);
    上面的参数ew就是一个委托(回调函数),再看这个参数的声明:
    delegate bool DelegateEnumWindow(IntPtr hWnd, int lParam);再看调用:
    DelegateEnumWindow dew = new DelegateEnumWindow(CallBackProc);//实例化委托
    EnumWindows(dew, 0);//调用API再看CallBacProc的定义:
    private bool CallBackProc(IntPtr hWnd, int lParam)
     {
       //在这里实现自己的查找逻辑,比如窗口的类名为XXXXX.
       StringBuilder sb = new StringBuilder(256);
       GetWindowText(hWnd, sb, sb.Capacity);
       if(sb.ToString() == "XXX")
       { 
          Console.WriteLine(" 找到了"); return true;
       }
       return false;
    }CallBackProc函数是由系统自动调用(调用者是EnumWindows函数),而不是由程序员调用
      

  2.   

    多谢yangglemu地回答,你说的这个我试过了,可是得不到我要的结果。
    我的sdk里面有2个函数作为参数1)void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmRawItem *myRawItem, void *pParam)2)void (__stdcall *lpfnCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmItem *myItem, void *pParam)如何实现对这2个函数的调用啊?
      

  3.   

    不是函数作为参数,是指向函数的指针,其实就是回调函数,关键是参数要正确,
    第一个是Ptr,第二个是整数,都没问题,关键是第三个是一个结构指针,要先定义结构(和C++里定义的一样),再跨平台申请内存,以这块内存的地址作为参数,最后一个是一个Void类型的指针,具体指向什么数据类型也要查看C++的定义,建议楼主查看设备开发手册说明,或者到该设备官网了解那个结构和Void指针的详细情况,否则调用一定失败
      

  4.   

    楼上的兄弟,我的结构体应该没有问题,别的函数都可以用的,
    估计我的错误应该在Void类型的指针上面,
    C++的示例代码里面是这样写的tltmStartReadingItems(m_hHandle, uiFields, boSetEAS, myRawCallback, myCallback, this);void __stdcall myRawCallback(HANDLE hHandle, int iReasonForCall, tltmRawItem *myItem, void *pParam)
    {

    }void __stdcall myCallback(HANDLE hHandle, int iReasonForCall, tltmItem *myItem, void *pParam)
    {

    }在C#里面我应该用什么指针来代替c++的this呢?
    我用了以后,报ArgumentNullException的错误。
      

  5.   

    能不能在C++里面再进行封装,去除掉this,然后再在C#里面调用呢?
      

  6.   

    使用delegate赋值给回调函数,这是对的。只有有两点:1. 大多数时候需要static的delegate,因为c之类的程序总是假设这些东西不会释放的。
    2. delegate的参数声明一定要跟c的一致。回调是可以执行的,跟普通的函数调用一样方便可靠。
      

  7.   

    楼上的兄弟,麻烦帮我看一下我的代码哪里错了//委托
    public delegate void lpfnRawCallBack(IntPtr hHandle, int iReasonForCall,ref tltmRawItem myRawItem, IntPtr pParam);public delegate void lpfnCallBack(IntPtr hHandle, int iReasonForCall, ref tltmItem myItem, IntPtr pParam);//lpfnRawCallBack用
    public static void myRawCallBack(IntPtr hHandle, int iReasonForCall, ref Tagsys.tltmRawItem myRawItem, IntPtr pParam)
    {

    }//lpfnCallBack用
    public static void myCallBack(IntPtr hHandle, int iReasonForCall, ref Tagsys.tltmItem myRawItem, IntPtr pParam)
    {
    。。
    }//实际调用
    lpfnRawCallBack rawBk = new lpfnRawCallBack(CLASS1.myRawCallBack);lpfnCallBack myBk = new lpfnCallBack(CLASS1.myCallBack);intErr = tltmStartReadingRawItems(this.m_handle, 1, 0,rawBk, IntPtr.Zero);
                
    intErr = tltmStartReadingItems(this.m_handle, 1, 0, rawBk, myBk, IntPtr.Zero);debug的时候,这两个函数都没有进去,抛ArgumentNullException的异常,请问这是什么原因呢?
      

  8.   

    IntPtr pParam也就是void *pParam是怎么初始化的?
      

  9.   

    就是这个不知道怎么办,
    示例代码只有c++,里面的void *pParam用的是this,那么我在.net里面应该用什么呢?
    请高手指点一下
      

  10.   

    看来只有用不安全代码解决了,因为this难办
      

  11.   

                System.Runtime.InteropServices.GCHandle gh = System.Runtime.InteropServices.GCHandle.Alloc(this, System.Runtime.InteropServices.GCHandleType.Pinned);
                IntPtr pParam = gh.AddrOfPinnedObject();
                intErr = tltmStartReadingRawItems(this.m_handle, 1, 0, rawBk, pParam);
                gh.Free();这样试试看能成功否获取到this的指针
      

  12.   

    回调函数用.NET中的委托处理
      

  13.   

    lpfnCallBack用
    public static void myCallBack(IntPtr hHandle, int iReasonForCall, ref Tagsys.tltmItem myRawItem, IntPtr pParam)
      

  14.   

    试过了,不可以
    抛下面的异常:
    System.ArgumentException:Object 包含非基元或非直接复制到本机结构中的数据看来只有通过别的方法取得当前实例的内存地址了。
    不能回调的话就郁闷了
      

  15.   

    还是没有办法取得this的内存地址,完蛋了
      

  16.   

    你的this指针代表的是class还是struct,声明的代码贴出来看看最坏状况是再写个DLL将这个DLL封装起来,提供一个去掉this指针的回调函数
      

  17.   


    this代表的是classC++的示例代码里面是这样写的tltmStartReadingItems(m_hHandle, uiFields, boSetEAS, myRawCallback, myCallback, this);void __stdcall myRawCallback(HANDLE hHandle, int iReasonForCall, tltmRawItem *myItem, void *pParam)
    {

    }void __stdcall myCallback(HANDLE hHandle, int iReasonForCall, tltmItem *myItem, void *pParam)
    {

    }
      

  18.   

    public static void myCallBack(IntPtr hHandle, int iReasonForCall, ref Tagsys.tltmItem myRawItem, class1 pParam)tltmStartReadingItems(m_hHandle, uiFields, boSetEAS, myRawCallback, myCallback, this);最后一个参数直接传你要的class类型试试,class1 是this代表的class类型,让编译器自己去进行地址转换
      

  19.   

    经过测试,抛了InvalidOperationException异常:此类型的层次结构中有 ComVisible(false)父级,因此不允许 QueryInterface 调用 IDispatch 或类接口。这个异常的资料很少,我把ComVisible改成true也不行
      

  20.   

    你的class的代码贴出来看看,怎么和ComVisible扯上关系了
      

  21.   

    //dll调用的类:tagsys
        //回调函数
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate void lpfnRawCallBack(IntPtr hHandle, Int16 iReasonForCall, ref Tagsys.tltmRawItem myRawItem, TAGSYSLP101 pParam); public class Tagsys
    {
            //// Raw Reading
            //int __stdcall tltmStartReadingRawItems(HANDLE hHandle, unsigned int uiFieldsMask, BOOL boSetEAS, void (__stdcall *lpfnRawCallBack)(HANDLE hHandle, int iReasonForCall, struct tltmRawItem *myRawItem, void *pParam), void *pParam);       
            [DllImport(ReaderList.READERS_TAGSYS_DLL, EntryPoint = "tltmStartReadingRawItems", CharSet=CharSet.Ansi, ExactSpelling=false,CallingConvention=CallingConvention.StdCall)]
            public static extern int tltmStartReadingRawItems(IntPtr hHandle, uint uiFieldsMask, Boolean boSetEAS,lpfnRawCallBack lpfnRawCallBack, TAGSYSLP101 pParam);}//实际应用:
    public unsafe class TAGSYSLP101 : AbstractReader
    {
    public TAGSYSLP101()
    {
    lpfnRawCallBack myRawCallBk = new lpfnRawCallBack(TAGSYSLP101.myRawCallBack);intErr = Tagsys.tltmStartReadingRawItems(this.m_device_handle, Tagsys.TLTM_ITEM_ALL, false, myRawCallBk, this);}public static void myRawCallBack(IntPtr hHandle, Int16 iReasonForCall, ref Tagsys.tltmRawItem myRawItem, TAGSYSLP101 pParam)
    {
         Console.WriteLine("here myRawCallBack");
    }
    }麻烦帮我看看对不对。另外,回调函数当中有数据结构作为参数,在回调的时候,会不会因为没有提前实例化而出错呢?
    public static void myRawCallBack(IntPtr hHandle, Int16 iReasonForCall, ref Tagsys.tltmRawItem myRawItem, TAGSYSLP101 pParam)
      

  22.   

    AbstractReader的定义看不到,另外TAGSYSLP101 根本就不需要继承,回调函数声明中直接用AbstractReader回调函数当中有数据结构作为参数,在回调的时候,会不会因为没有提前实例化而出错呢?回调函数当中有数据结构作为参数要看DLL中是否有对这个参数作过什么处理,最好是先实例化
      

  23.   

    我也遇到过这样的问题  我是封装了一个中间dll  解决的 
      

  24.   

    AbstractReader的定义看不到,另外TAGSYSLP101 根本就不需要继承,回调函数声明中直接用AbstractReader按照上面的改了没有报错了,但是回调函数还是没有被执行,会不会还是参数不对的原因呢?
    把数据结构改成类会不会好一些?
      

  25.   

    委托
    public delegate bool CallBack(int hwnd, int lParam);