用VS写的动态库,Delphi写的上位机。其他接口调用都没问题,动态库和上位机分别编译也没问题。但是动态库回调上位机的回调函数时,弹出“access violation at addressXXXX ,write of addressXXXX”
上位机和动态库中分别的操作是:
上位机中:
回调函数声明TOnResponse =procedure(sCmdBack:PChar) of object;回调函数有声明,有定义。
调用回调函数的接口函数function RegisterHWCallback(aCallback:TOnResponse):Integer;stdcall;external 'Hardware.dll';
动态库中:
回调函数声明typedef void (*TOnResponse)(PCHAR sCmdBack);
调用回调函数的接口函数extern"C"_declspec(dllexport)int _stdcall RegisterHWCallback(TOnResponse aCallback)一旦进入该接口函数,即使里面是空操作,跳出这个接口函数时都会弹出“access violation at addressXXXX ,write of addressXXXX”
这个问题解决思路是什么,之前为这个动态库写过vs的上位机,都没问题。但是链接上对方的Delphi上位机后就弹出了这个问题。

解决方案 »

  1.   

    TOnResponse =procedure(sCmdBack:PChar) of object;
    这里有of object啊!跟动态库的声明对应不上吧?
      

  2.   

    TOnResponse =procedure(sCmdBack:PChar) of object;
    改成:
    TOnResponse =procedure(sCmdBack:PChar) ; cdecl;
      

  3.   

    抱歉,那做不到,除非你让微软把编译器改了。
    你的Delphi程序中,TOnResponse =procedure(sCmdBack:PChar) of object;这声明了一个方法指针,由于你没有指出调用约定,默认是Borland的register约定,所以对这个回调函数正确的参数传入是:eax=self(C++中的this),edx=sCmdBack,函数自己做栈平衡;而你的VC代码中定义的,typedef void (*TOnResponse)(PCHAR sCmdBack);使用cdecl调用约定,sCmdBack使用栈传递,调用者做栈平衡。
    你看看两者能不能对上?整个就是猴吃麻花---满拧。如果你非要在C代码中调用Delphi的方法,那你就不能直接用函数指针调用,要自己写一个调用转换函数,比如:
    void CallBackThunk(TOnResponse &P, PCHAR sCmdBack);
    在其内部用嵌入汇编模拟方法指针调用,但是C代码并不知道被调用方法的实例指针,这也是一个严重隐患,所以最好还是把Delphi的回调函数定义改一下。
      

  4.   

    如果上位机和动态库都改成stdcall的调用约定。Delphi程序中依然声明方法指针
    TOnResponse =procedure(sCmdBack:PChar) of object;对应VC动态库里要怎么声明才能与这个方法指针对应呢
      

  5.   


    这样的话参数传递问题解决了,主要问题在于C代码并不知道被调用方法的实例指针,你还得修改RegisterHWCallback把它传给C代码:
    int _stdcall RegisterHWCallback(TOnResponse aCallback, void *Sender);
    这个Sender你得保存起来,调用Delphi回调函数的时候要用到:
    typedef void (__stdcall *TOnResponse)(Void *Sender, PCHAR sCmdBack);