DLL 應用 - 設計可抽換的模組(2)
2008-04-09 04:28:15来源:互联网 阅读 ()
以下會一步步實作出一個具體而微的範例,你可以把這個範例視為一個基礎的框架(framework),稍加修改就可以運用於實際的專案開發上面。
描述需求
讓我們來簡單地分析一下應用程式的需求,假設原本的開發方式是將所有的程式單元編譯連結成一個可執行檔,現在要將應用程式的各個功能切割為獨立的模組,例如:
--- 客戶資料維護作業(Customer.DLL)
主程式(Main.exe)--- --- 產品資料維護作業(Employee.DLL)
--- 訂單資料維護作業(Orders.DLL)
其中每個 DLL 都是在使用者執行該項功能的時候才動態載入,而且每個 DLL 裡面至少包含一個 Form,為了有別於一般的 DLL,以下就以 plugin 稱之。我們預期各 plugin DLL 所包含的 Form 會有一些共同的屬性和行為,因此把這些共同點放到一個基礎視窗類別裡面,讓其他 Form 繼承自這個基礎類別。它們的關係看起來像這樣:

每一個維護作業都需要開啟一個視窗,因此主程式的責任之一便是建立並顯示 DLL 裡面的視窗。我們希望每一個維護作業的視窗關閉後才能執行另一個維護作業,所以使用 ShowModal 的方式顯示視窗。做一些簡單的分析之後,可以得到主程式在執行每項作業時所需的共同步驟:
- 載入指定的 plugin DLL。
- 建立並顯示 plugin DLL 裡面的 Form 物件。
- 釋放 Form 物件。
- 釋放 plugin DLL。
其中載入與是釋放 plugin DLL 的工作由主程式負責,而前面有提過 DLL 中的物件必須由 DLL 自己來建立,因此建立、顯示以及釋放 Form 物件的工作都由 plugin DLL 來負責提供函式,主程式只要在適當時機去呼叫它們就行了。
主程式
在主程式中加入一個執行 plugin 的方法,此方法需要一個參數指定 DLL 的檔名以便將其載入執行,像這樣:
procedure TMainForm.RunPlugin(const FileName: string);
var
ADllHandle: THandle;
APlugin: IPlugin;
AFormHandle: THandle;
begin
ADllHandle := SafeLoadLibrary(FileName);
if ADllHandle <> 0 then
begin
APlugin := DllCreatePlugin(ADllHandle, Application.Handle);
try
AFormHandle := APlugin.CreateForm(Handle);
APlugin.ShowModalForm;
APlugin := nil;
FreeLibrary(ADllHandle);
except
FreeLibrary(ADllHandle);
raise;
end;
end
else
ShowMessage(''''無法載入函式庫: '''' FileName);
end;
從以上程式碼可以看出主程式載入 DLL 之後會呼叫 DllCreatePlugin 來建立 plugin 物件並且取得其介面參考,接著主程式就利用該介面參考來存取 plugin 物件提供的服務,包括建立視窗,顯示視窗等等。很明顯地,IPlugin 介面是主程式和 plugin DLL 之間溝通的橋樑,而且 IPlugin 介面至少要提供下列方法:
CreateForm - 建立 Form 物件
ShowModalForm - 顯示視窗
DestroyForm - 摧毀 Form 物件
眼尖的讀者可能會發現,上面的程式中並沒有呼叫 DestroyForm,而且也沒有呼叫類似 DllDestroyPlugin 的函式來摧毀 plugin 物件,這些物件什麼時候會被釋放掉?
它們是自動被釋放掉的。由於 Form 物件的建立是透過 plugin 物件來完成,所以我打算把摧毀 Form 物件的責任交給 plugin 物件,也就是當 plugin 物件摧毀時會自動將 Form 物件一併釋放掉;而為了簡化摧毀 plugin 物件的動作,我讓 plugin 物件具有自動參考計數的能力,這麼一來只要該物件沒有人使用它(物件的參考計數為 0)就會自動釋放掉了,做法很簡單,只要讓實作 IPlugin 的類別繼承自 TInterfaceObject 就行了,其他細節都由 VCL 幫我們完成了。
接著看 DllCreatePlugin 函式:
type
TCreatePluginFunc = function (hApp: THandle): IPlugin; stdcall;
const
SDllCreatePluginFuncName = ''''CreatePlugin'''';
implementation
resourcestring
sErrorLoadingDLL = ''''無法載入模組!'''';
sErrorDllProc = ''''無法呼叫 DLL 函式: %s'''';
function DllCreatePlugin(hLib, hApp: THandle): IPlugin;
var
pProc: TFarProc;
CreatePluginFunc: TCreatePluginFunc;
begin
pProc := GetProcAddress(hLib, PChar(SDllCreatePluginFuncName));
if pProc = nil then
raise Exception.CreateFmt(sErrorDllProc, [SDllCreatePluginFuncName]);
CreatePluginFunc := TCreatePluginFunc(pProc);
Result := CreatePluginFunc(hApp);
end;
DllCreatePlugin 會嘗試從指定的 DLL 模組中呼叫函式 ''''CreatePlugin'''' 來建立 plugin 物件,並且傳回 plugin 物件的介面參考,參數 hLib 是 DLL 代碼,而 hApp 則直接傳遞給 DLL 的CreatePlugin 函式,這個參數的作用稍後會解釋。
至此主程式所需的程式碼大致上已經完成了,接下來看看 DLL 的 CreatePlugin 函式。
DLL 的輸出函式
我們的 plugin DLL 只有輸出一個函式供外界呼叫,就是前面提到的 CreatePlugin,其函式原型為:
function CreatePlugin(hApp: THandle): IPlugin; export; stdcall;
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash
