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

2008-04-09 04:28:15来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

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

作者:蔡煥麟
日期:Jan-2-2001 

摘要:介紹以 DLL 來切割應用程式的實作方式,其中包含介面程式設計的技巧以及運用 Design Patterns 來解決設計上的問題。

前言

DLL(Dynamic Link Library,動態聯結函式庫)就目前來講已經不是什麼了不得的技術,坊間書籍隨手撿一本視窗程式設計或 Delphi 的書籍都可以找到 DLL 的相關說明,少這一篇也不算少,之所以寫這篇文章,一方面是給自己的學習心得作個記錄,一方面也提供給有需要的人參考;而本文的主題--設計動態載入的模組--說穿了也只是提供一個把 Form 包在 DLL 裡面的實作方法,儘管如此,我還是希望你能在其中發現一些比較不一樣的東西。

由於現有關於 DLL 的文件資料已經很多,在此不多做重複,因此在閱讀本文時會需要一些 DLL 的基礎知識或者 DLL 的撰寫經驗,這樣閱讀起來會比較輕鬆。以下就重點式地列出一些基礎觀念:

  • 靜態連結與動態連結的差異。
  • 了解如何宣告 DLL 輸出函式(exported functions)以及如何在外部呼叫它們。
  • 各種呼叫慣例(calling conventions)的差異。
  • 何謂 DLL hell(1)以及它對應用程式的維護有何影響。

DLL 在使用上又有靜態與動態載入的區別,所謂「靜態載入的 DLL」意指在編譯時期已經確定要連結的 DLL 是哪一個,而且會在行程初始化的階段就被載入,Delphi 的 VCL packages 即屬此類。動態載入的 DLL 則是執行時期需要時才載入,在程式撰寫上比靜態載入的方式麻煩些,但較有彈性,且應用程式啟動的速度也較快。

本文所要討論的就是以動態載入的 DLL 來實作可抽換的應用程式模組。

以 DLL 切割應用程式

一般來說,使用 DLL 有下列優點:

  • 節省記憶體。多個應用程式使用同一個 DLL 時,該 DLL 只會被載入一次,甚至可以用到時才載入 DLL,且用完立即釋放。
  • 程式碼重複使用,可讓不同的程式語言使用。
  • 應用程式模組化,可降低應用程式的複雜度,程式更新維護時較方便。
  • 可支援設計多國語言的應用程式。你可以把每一種語言的字串資源分別存放在一個 DLL 裡面,程式執行時便可以動態切換程式所使用的語言。

但也會一些困難必須克服,當我們要將應用程式切割成數個 DLL 模組的時候,通常會碰到以下幾個問題:

  1. DLL 如何輸出(export) VCL 物件?
  2. 如何將一個 Form 包在 DLL 裡面以供外部使用?
  3. DLL 之間如何共享變數?

基本上,如果你撰寫成 package 的形式就沒有上述問題了,但你可能會遇到其他麻煩,例如:名稱衝突的問題,這包括了型態、單元名稱、函式名稱的衝突,在此之前我也曾試著以 package 的方式來撰寫可抽換的模組,但名稱衝突的問題令我覺得蠻困擾。我也曾在另一份文件中提及此事,以下這段文字是從該文轉貼上來的(2):

「在撰寫幾個 package 的測試程式之後,我還是沒有將 package 應用在實際的專案開發中,而仍然使用 DLL,其最主要的原因,正是 package 優於 DLL 之處--可以共享變數。這項功能的立意很好,但也帶來了另一些限制,主要是名稱衝突的問題,使得共用的 unit 一定要放在 package 裡面,否則當兩個 package 包含了相同的 unit,其中一個就無法載入,我們覺得這會造成麻煩。另外,由於其他的小組成員對於 package 的使用不熟,容易出 trouble(例如:project 要加入 .dcp 之類的),這也是考量之一。」

在 DLL 之間共享變數的問題可以透過記憶體映射檔(memory-mapped file)來解決,你可以在文後所附的參考資料中找到相關資訊,這裡就不贅述。而在 DLL 中輸出 VCL 物件(例如:string)時得注意以下幾點:

  • 在 DLL 和其用戶端程式的 Uses 子句裡頭的第一個單元必須是 ShareMem。
  • BORLNDMM.DLL 必須跟著你的應用程式一起發佈。
  • 如果你修改了輸出物件的類別定義而使得原有物件的記憶體佈局改變,比如說加入一個 Integer 型態的私有成員,用戶端程式就必須重新編譯,如果使用舊的用戶端程式來呼叫新的 DLL 函式,應用程式就會發生錯誤甚至導致當機。

與其隨時注意這些規則,也許選擇可以完全避開這些問題的方法會比較好,我的意思是使用 Windows 的標準型別來傳遞資料,例如要傳遞字串,就用 PChar 來代替 string。對其他較為複雜的結構,可以使用介面來解決,這意味著兩件事情:

  1. 輸出的型態是個抽象類別(abstract class)或介面(interface)。
  2. 物件應由 DLL 來建立(用戶端程式不知道物件的記憶體佈局)。

符合了以上的規則,對於如何將 Form 物件包在 DLL 裡面的問題也就迎刃而解,稍後就會講到這部分如何實作。

介面(interface)在物件導向的領域裡是一個很重要的觀念,它描述了服務提供者和使用者之間的權責,或者說定義了兩個物件之間溝通的方式,通常這個溝通方式一經制定就不會修改(理想狀況下),因此介面亦可視為物件之間的合約。以 OOP 的角度來看,介面就是一組公開的方法(public methods),跟類別不同之處是它沒有 private 及 protected 等存取等級的區別,不可以包含資料成員,也沒有實作的程式碼,它就只是很單純的....呃...介面。在一個複雜的系統裡面,這種單純顯得特別珍貴,常常得經過一番深思熟慮之後才能萃取出較為抽象的成分,這不但有助於你在設計時以比較抽象的層次去思考,同時設計出來的介面也比較能夠再拿來重複使用。以用戶端的角度來看,介面把系統背後的複雜度隱藏了起來,用戶端就只需專注在它需要的部分,使用上會比較容易。

設計可抽換的模組

所謂可抽換的模組,就是指在程式執行時動態地載入與釋放的模組,對於規模較龐大,功能較複雜的應用程式來說,將應用程式切割成數個獨立運作的模組有以下優點:

  • 應用程式部署的組態更加彈性(例如:有些模組僅包裝於某種版本中)。
  • 減少應用程式每次更新版本的檔案大小。
  • 有利於明確劃分小組成員的權責。
  • 有效地降低單一程式的複雜度,程式較易於維護。

    标签:

    版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
    特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:界面(FORM)自动生成工具

下一篇:数据库的一种完全面向对象设计模式(包含实例) Rayphrank原创