用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上位機后就彈出了這個問題。
uj5u.com熱心網友回復:
TOnResponse =procedure(sCmdBack:PChar) of object;這里有of object啊!跟動態庫的宣告對應不上吧?
uj5u.com熱心網友回復:
那改動態庫的話,動態庫里的宣告應當怎么寫啊uj5u.com熱心網友回復:
TOnResponse =procedure(sCmdBack:PChar) of object;改成:
TOnResponse =procedure(sCmdBack:PChar) ; cdecl;
uj5u.com熱心網友回復:
抱歉,是改動態庫,不改上位機。動態庫是VS寫的。uj5u.com熱心網友回復:
抱歉,那做不到,除非你讓微軟把編譯器改了。你的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的回呼函式定義改一下。
uj5u.com熱心網友回復:
如果上位機和動態庫都改成stdcall的呼叫約定。Delphi程式中依然宣告方法指標TOnResponse =procedure(sCmdBack:PChar) of object;對應VC動態庫里要怎么宣告才能與這個方法指標對應呢
uj5u.com熱心網友回復:
這樣的話引數傳遞問題解決了,主要問題在于C代碼并不知道被呼叫方法的實體指標,你還得修改RegisterHWCallback把它傳給C代碼:
int _stdcall RegisterHWCallback(TOnResponse aCallback, void *Sender);
這個Sender你得保存起來,呼叫Delphi回呼函式的時候要用到:
typedef void (__stdcall *TOnResponse)(Void *Sender, PCHAR sCmdBack);
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/100411.html
