手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>程序设计>delphi>列表

DLL 應用 - 設計可抽換的模組

来源:互联网 作者:西部数码 时间:2008-04-09
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!
inherited Destroy; end; function TPlugin.CreateForm(hMainForm: THandle): THandle; begin if FForm = nil then begin Assert(g_ConcreteClass <> nil, ''''未設定欲實體化的 Form 類別名稱!''''); FForm := g_ConcreteClass.Create(Application); FForm.MainFormHandle := hMainForm; end; Result := FForm.Handle; end; procedure TPlugin.DestroyForm; begin if FForm <> nil then begin FForm.Release; FForm := nil; end; Application.ProcessMessages; end; function TPlugin.ShowModalForm: Integer; begin if FForm = nil then raise Exception.Create(''''DllExoprt: 視窗尚未建立!''''); Result := FForm.ShowModal; end; initialization g_DllAppHandle := Application.Handle; end.

 

範例程式

範例程式可以按此處下載:PluginDLL.zip

下載壓縮檔並解開後,請先閱讀其中的 readme.txt。

可改進之處

你可以試著修改範例程式並強化它,使它可以當作實際開發專案的基礎框架,以下列出幾項可能的改進之處:

  • 賦予 TBaseForm 基本的資料處理能力,像是新增、修改、刪除...等。
  • 修改使之適用於 modeless form 及 MDI 應用程式。這意味著釋放 DLL 的時機也會改變,你可能會需要一個串列結構將載入的 DLL 記錄起來,通常一個 TStringList 就可以做到。
  • 讓一個 plugin 物件可以建立並維護多個不同類型的 Form 物件。

你可能會希望一個 DLL 裡面可以提供多種 form 物件供主程式使用,這些 form 物件之間可能有某種程度的相似或相依關係。根據此需求我們可以整理出 plugin 物件具備以下兩個特性:

  1. plugin 物件可以建立多種不同類型的 form 物件,而它們都是繼承自基礎的表單類別 TBaseForm。
  2. 一個 DLL 裡面只需要一個 plugin 物件。

根據 [GHJV95] 書中的定義,Abstract Factory 的用意是:

「提供一個介面來建立同一族系或相依的物件,而毋須指明它們的具象類別(concrete class)」

而 Factory 通常也被實作成 Singleton,這些特性清楚地告訴我們 plugin 物件非常適合實作成一個 Factory。你可能需要在 TPlugin 類別裡面提供一個 RegisterClass 方法,這個方法取代了原先的類別參考型態,原本在 TBaseForm 子類別的單元裡設定 g_ConcreteClass 的敘述將會改成:

  PluginFactory.RegisterClass(TForm1);

註冊過的類別資訊將會被記錄在一個串列裡面。主程式則可以在建立 form 物件時透過字串來指定要建立的 form 類別名稱,像這樣:

  APlugin.CreateForm(''''TCustomerForm'''');

plugin 物件的 CreateForm 方法就會到串列中搜尋註冊過的類別,取得對應的類別參考並建立其實體(是不是有點像 COM 所做的事情?)。

嗯,我想這樣的提示應該夠了,最重要的還是要自己實際去撰寫及除錯程式碼以獲得更深刻的體會,真能如此,這個 Design Pattern 就會完全融入你的知識體系裡面,以後不加思索便可以運用自如了。

結語

在這份文件裡面主要是介紹以 Delphi 來設計 plugin 模組的實作過程,其中運用了介面程式設計的技巧(包括介面的參考計數以及物件生命週期的控制)以及 Design Patterns 來解決設計時遭遇的問題,這也是學習的重點之一。

在一個多人開發的專案裡,如果您的責任是設計主程式框架,當您要以 DLL 來切割應用程式時會怎麼做呢?這篇文章裡面展示了一種可能的設計方式,如果您有不同的想法或者對本文有任何建議,都很歡迎您來信指教。

Delphi 的 DLL 記憶體漏洞

最後,雖然不是本文的主題,但也頗值得注意的,就是動態載入的 DLL 在釋放時會有 4K 的記憶體漏洞,而且 Delphi 5 和 6 都有這個問題,你可以閱讀下面兩份文件,其中有詳細的說明並提供解決之道:

  • Memory Lost And Found...And Release by Roy Nelson.
    http://www.thedelphimagazine.com/samples/1328/1328.htm
  • VCL leak fix for dynamic DLLs by Dejan Maksimovic.
    http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=16380

 

註1.

 

由於 DLL 版本的更新可能使得原本叫用它的程式無法正常運作,因此以不同的檔名區分版本(例如:MFCxx.DLL),使得硬碟裡面必須保存同一種 DLL 的多個版本,即使使用者將應用程式移除了,卻不敢放心的移除相關的 DLL 檔案,以免其他應用程式因為缺少了這個檔案而無法運作,這種情況所形成的問題稱為 DLL hell。COM 的出現有解決此問題的企圖(透過執行時期詢問元件支援的介面),但似乎並不理想,直到 .NET 的問世而終於有了比較好的解決方案。
註2. 可以到 http://www.geocities.com/huanlin_tsai/ 的〔心得分享〕區找到相關文章。不可諱言,以上所說的難免摻雜了個人的因素,也許其他人在使用 package 時並未發生上述問題,而且使用 package 的方式也有許多優點,在此僅將個人實際應用時的狀況與感覺描述出來,若有謬誤之處尚請各方不吝指正。 註3. Singleton 樣式:提供單一窗口來建立類別的實體,以確保只有一個類別的實體存在。參考 [GHJV95] 的書。

參考資料