字符串參數(shù)
前面曾提到過,為了保證DLL參數(shù)/返回值傳遞的正確性,,尤其是為C++等其他語言開發(fā)的宿主程序使用時(shí),,應(yīng)盡量使用指針或基本類型,因?yàn)槠渌Z言與Delphi的變量存儲(chǔ)分配方法可能是不一樣的,。C++中字符才是基本類型,,串則是字符型的線形鏈表。所以最好將string強(qiáng)制轉(zhuǎn)換為Pchar,。
如果DLL和宿主程序都用Delphi開發(fā),,且使用string(還有動(dòng)態(tài)數(shù)組,它們的數(shù)據(jù)結(jié)構(gòu)類似)作為導(dǎo)出例程的參數(shù)/返回值,,那么添加ShareMem為工程文件uses語句的第一個(gè)引用單元,。ShareMem是Borland共享的內(nèi)存管理器Borlndmm.dll的接口單元。引用該單元的DLL的發(fā)布需要包括Borlndmm.dll,,否則就得避免使用string,。
在DLL中建立及顯示窗體
凡是基于窗體的Delphi應(yīng)用程序都自動(dòng)包含了一個(gè)全局對(duì)象Application,,這點(diǎn)大家是很熟悉的。值得注意的是Delphi創(chuàng)建的DLL同樣有一個(gè)獨(dú)立的Application,。所以若是在DLL中創(chuàng)建的窗體要成為應(yīng)用程序的模式窗體的話,,就必須將該Application替換為應(yīng)用程序的,否則結(jié)果難以預(yù)料(該窗體創(chuàng)建后,,對(duì)它的操作比如最小化將不會(huì)隸屬于任何主窗體),。在DLL中要避免使用ShowMessage而用MessageBox。
創(chuàng)建DLL中的模式窗體比較簡單,,把Application.Handle屬性作為參數(shù)傳遞給DLL例程,,將該句柄賦與Dll的Application.Handle,然后再用Application創(chuàng)建窗體就可以了,。
無模式窗體則要復(fù)雜一些,,除了創(chuàng)建顯示窗體例程,還必須有一個(gè)對(duì)應(yīng)的釋放窗體例程,。對(duì)于無模式窗體需要十分小心,,創(chuàng)建和釋放例程的調(diào)用都需在調(diào)用程序中得到控制。這有兩層意思:一要防止同一個(gè)窗體實(shí)例的多次創(chuàng)建,;二由應(yīng)用程序創(chuàng)建一個(gè)無模式窗體必須保證由應(yīng)用程序釋放,,否則假如DLL中有另一處代碼先行釋放,再調(diào)用釋放例程將會(huì)失敗,。
初始化COM庫
如果在DLL中使用了TADOConnection之類的COM組件,,或者ActiveX控件,調(diào)用時(shí)會(huì)提示 “標(biāo)記沒有引用存儲(chǔ)”等錯(cuò)誤,,這是因?yàn)闆]有初始化COM,。DLL中不會(huì)調(diào)用CoInitilizeEx,初始化COM庫被認(rèn)為是應(yīng)用程序的責(zé)任,,這是Borland的實(shí)現(xiàn)策略,。
你需要做的是1、引用Activex單元,,保證CoInitilizeEx函數(shù)被正確調(diào)用了
2,、在單元級(jí)加入初始化和退出代碼:
initialization
Coinitialize(nil);
finalization
CoUninitialize;
end.
引出DLL中的對(duì)象
從DLL窗體的例子中可以發(fā)現(xiàn),將句柄做為參數(shù)傳遞給DLL,,DLL能指向這個(gè)句柄的實(shí)例,。同樣的道理,從DLL中引出對(duì)象,,基本思路是通過函數(shù)返回DLL中對(duì)象的指針,,將該指針賦值到宿主程序的變量,使該變量指向內(nèi)存中某對(duì)象的地址,。對(duì)該變量的操作即對(duì)DLL中的對(duì)象的操作,。
聲明時(shí)要包括stdcall后綴,,這樣才能保證調(diào)用Delphi開發(fā)的DLL的例程中類似PChar這樣的參數(shù)值傳遞正確。大家有興趣可以試驗(yàn)一下,,不加入stdcall或者safecall后綴執(zhí)行上面代碼,,將不能保證成功傳遞字符串參數(shù)給DLL函數(shù)。
為了保證生成的DLL能正確與C++等語言兼容,,需要注意以下幾點(diǎn):
盡量使用簡單類型或指針作為參數(shù)及返回值的類型。這里的簡單類型是指C++的簡單類型,,所以string字符串類型最好轉(zhuǎn)換成Pchar字符指針,。直接使用string的DLL例程在Delphi開發(fā)的程序中調(diào)用是沒有問題的(有資料指出需加入ShareMem做為第一單元以確保正確),但如果使用C++或其他語言開發(fā)的程序調(diào)用,,則不能保證參數(shù)傳遞正確,;
雖然過程是允許的,但是最好習(xí)慣全部寫成函數(shù),。過程則返回執(zhí)行正確與否的true/false,;
對(duì)于參數(shù)的指示字比如const(只讀)、out(只寫)等等,,為保證調(diào)用的兼容性,,最好使用缺省方式(缺省var,即可讀寫的地址),;
使用stdcall聲明后綴,,以保證正確的異常處理。16位DLL無法通過這種方式處理異常,,所以還得在例程最外層用Try … Except將異常處理掉,;
一般不使用far后綴,除非為了保持與16位兼容,。