Delphi使用模塊化開發,可以采用DLL或者BPL,兩者的區別是BPL只能被同版本的Delphi使用,DLL可以被不同版本和不同開發工具的開發的軟件調用。
因此我們的軟件大多使用Delphi作為界面以及部分DLL模塊的開發工具。
DLL模塊之間通過接口方式調用。
1.對象創建采用工廠模式,每個DLL負責某個對象或若干個對象的創建及釋放,例如:
DLL工程為http客戶端(prjHttp.DLL)模塊,通過DLL導出的GetHttpClientFactory獲取http客戶端工廠接口,通過接口創建Http客戶端和釋放Http客戶端,工程
包括3個文件:工程文件,實現單元,接口單元。
調用此DLL的程序僅需要包含接口單元。
DLL工程文件
System.SysUtils, System.Classes, utHTTPClient .
utHttpClient示例
= Destroy; = Destroy; CreateHttpClient( DestroyHttpClient( Assigned(HttpClients) == Assigned(HttpClients) .
utHttpInterface接口文件示例
= = = = = ====== SetValue( ServerAddr: PAnsiChar; ServerPort: Integer; = = = OnHeader( Http:IHTTPClientConnection; Header:Pointer; OnStartReceiveContent( Http:IHTTPClientConnection; OnReceiveProgress( Http:IHTTPClientConnection; OnError( Http:IHTTPClientConnection; == = CreateHttpClient( DestroyHttpClient( .
調用prjHttp.DLL的Delphi工程可以包含下面的單元以及上面的接口單元utHttpInterface.pas即可
將utHttpDLL.pas中的
//{$define utHttpDLL)
去掉注釋,即可以將http客戶端這些代碼包含到Delphi工程中。
// = = == LibHandle <> INVALID_HANDLE_VALUE = GetProcAddress(LibHandle, Assigned(P) = Exception.Create( + Assigned(HttpClientFactory) Exception.Create(DLLName + LibHandle <> INVALID_HANDLE_VALUE = == .
2.DLL中輸出接口對象的生命周期管理
Delphi對接口采用引用計數的方法管理對象生命周期,但是DLL中輸出的對象可能不是被Delphi調用,其引用計數不一定正確,因此DLL中接口對象的生命周期不由Delphi編譯器自動生成的代碼管理,而是程序員自己控制,所以上面
的工廠包括構造和解析兩個接口對象的生命周期管理方法。
所有接口對象應該集成自下面的接口,而不應該繼承自Delphi自帶的TInterfacedObject:
TIntObject = QueryInterface( IID: TGUID; Obj): HResult; _AddRef: Integer; _Release: Integer; TIntObject.QueryInterface( IID: TGUID; GetInterface(IID, Obj) = == -= - ;
3.自管理接口對象在Delphi調用注意事項
1)接口賦值
錯誤代碼:(Delphi編譯器產生代碼會先判斷接口指針是否為nil,如果非nil自動調用接口的_Release方法)
=, ,,
建議代碼:
):==FServer.Param; //
2)局部接口變量
錯誤代碼:
=TTcpConnectionServerEventAdapter.Create(Self =TTcpConnectionEventAdapter.Create(Self =TConnectionEventAdapter.Create(Self =, ,, =;
上面代碼中運行退出後,Delphi編譯器會在此代碼後面自動調用P1._Release; P2._Release,
建議代碼:
=TTcpConnectionServerEventAdapter.Create(Self =TTcpConnectionEventAdapter.Create(Self =TConnectionEventAdapter.Create(Self =, ,, =
;
3)函數返回值為接口指針
如下面的示例中FServer.Param定義為function THttpServer.Param:IHttpServerParam,返回的是接口類型,下面的代碼直接調用Param.SetValue方法:
=TTcpConnectionServerEventAdapter.Create(Self =TTcpConnectionEventAdapter.Create(Self =TConnectionEventAdapter.Create(Self RegistObserver(FServer, FServerEvent); TcpClientFactory.CreateTcpConnection(FRemote); RegistObserver(FRemote,FTcpConnectionEvent); ;
上面的代碼,Delphi編譯器會自動生成兩個接口變量,保存FServer.Param和FRemote.Param,由於FServer和FRemote為TTcpServerSplitter對象的全局變量,所以接口在TTcpServerSplitter對象釋放時,被調用_Release
將導致內存訪問異常。
=TTcpConnectionServerEventAdapter.Create(Self =TTcpConnectionEventAdapter.Create(Self =TConnectionEventAdapter.Create(Self RegistObserver(FServer, FServerEvent); TcpClientFactory.CreateTcpConnection(FRemote); RegistObserver(FRemote,FTcpConnectionEvent); Pointer(P2):=nil; end;
4)對象中的接口變量,在對象釋放時,需要將接口變量清空。
;