在用Delphi 3.0開發軟件時,出現了硬件驅動程序(DLL)中的函數和過程不能正常調用的問題,該硬件由英國Schlumberger公司生產,驅動程序用匯編語言編寫的。其《編程指南》給出的Microsoft C的示范程序均能正常運行。但運行此軟件時現出的錯誤提示為:
Access violation at address ×××××××× in module……
經仔細分析,才發現問題出現在函數調用模式上。
Delphi 3.0支持五種調用模式:register、cdecl、pascal、stdcall和safecall。根據調用模式的不同,參數可以通過CPU的寄存器或堆棧傳遞給函數和過程。register模式使用CPU的三個寄存器傳遞參數,而其它模式則用堆棧來傳遞參數。在register和pascal模式下從左至右傳遞參數,即參數表中最左邊的參數最先被求值並傳遞,而最右邊的參數最後求值並傳遞。另三種模式cdecl、stdcall和safecall則從右至左傳遞參數。這些模式中除了cdecl外,都是由過程和函數在返回時清除堆棧中的參數,而對於cdecl模式,需由調用者在調用結束時清除堆棧中的參數。
如何選擇調用模式,有以下三條規則:
1.Delphi 3.0使用register模式作為缺省調用模式以提高運行效率。
2.如果有調用關系的幾個模塊是用不同語言編寫的,其接口應使用stdcall模式。
3.如果要實現雙界面函數和過程,應使用safecall模式。
所以解決我們的問題只要選用stdcall模式即可,Schlumberger公司的《編程指南》上在Microsoft C環境下的DLL函數說明(僅舉兩例)為:
void(FAR PASCAL *Imp_ Connect)(unsigned short far*,short far*);
void(FAR PASCAL *Imp_ Init)(short far*,short far*);
相應的在Delphi 3.0下DLL函數引入說明為:
procedure Imp_ Connect(var CardAddress:Word;var CardHandle:smallint);stdcall;
procedure Imp_ Init(var Poll_Tab:smallint;var ErrorFlag:smallint;var CardHandle:smallint);stdcall;
這樣修改以後,程序即可正常運行(原來我們沒有說明調用模式,即使用缺省的register模式),由此我們也可得出一個經驗:對一些高版本的新軟件,使用時要注意改進和擴充,並經常看看幫助文件,定會大有裨益。