初探Delphi 7 中的插件編程_第1頁
初探Delphi 7 中的插件編程_第2頁
初探Delphi 7 中的插件編程_第3頁
初探Delphi 7 中的插件編程_第4頁
初探Delphi 7 中的插件編程_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、初探Delphi 7 中的插件編程  1 前言 1.1 寫作目的 我寫Delphi程序是從MIS系統(tǒng)入門的,開始嘗試子系統(tǒng)劃分的時候采用的是MDI窗體的結(jié)構(gòu)。隨著系統(tǒng)功能的擴充,不斷有新的子系統(tǒng)加入系統(tǒng)中,單個工程會變得非常大,每次做一點修改都要重新編譯,單個工程的形式也不利于團隊協(xié)作。為了提高工作效率,我希望利用DLL動態(tài)鏈接庫的形式實現(xiàn)插件結(jié)構(gòu)的編程。 插件結(jié)構(gòu)的編程需要一個插件容器來控制各DLL的運行情況,將劃分好的每個子系統(tǒng)安排到一個DLL庫文件中。對每個DLL程序需要為容器預留接口函數(shù),一般接口函數(shù)包括:啟動調(diào)用DLL庫的函數(shù)、關(guān)閉DLL庫的函數(shù)。通過接口函數(shù),插

2、件容器可以向DLL模塊傳遞參數(shù)實現(xiàn)動態(tài)控制。具體實現(xiàn)細節(jié)我將在下文說明并給出響應代碼。 1.2 閱讀對象 您可能需要先了解一下DELPHI中UNIT的結(jié)構(gòu),工程的結(jié)構(gòu)。本文沒有深入討論DLL編程的理論細節(jié),只是演示了一些實用的代碼,我當時學習的是劉藝老師的DELPHI深入編程一書。 2 示例程序簡介 為了便于閱讀我將使用一個MIS系統(tǒng)的部分程序代碼演示插件編程的一些方法。示例程序是典型的C/S結(jié)構(gòu)DBMS應用程序,我們關(guān)注的部分將是框架程序(下文簡稱Hall)的控制語句和dll插件程序的響應控制。 2.1 程序結(jié)構(gòu) 插件容器Hall使用一個獨立的工程創(chuàng)建,Hall的主窗口的作用相當于MDI程序

3、中的MDI容器窗體,Hall中將顯式調(diào)用Dll中的接口函數(shù)。 每個插件程序獨立使用各自的工程,與普通工程不同的是,DLL工程創(chuàng)建的是Dll Wizard,相應編譯生成的文件是以DLL為后綴。2.2 接口設(shè)計 實例程序Narcissus中我們預留兩個接口函數(shù): ShowDLLForm 該函數(shù)將應用程序的句柄傳遞給DLL子窗口,DLL程序?qū)討B(tài)創(chuàng)建DLL窗體的實例。還可以將一些業(yè)務(wù)邏輯用參數(shù)的形式傳遞給DLL子窗口,比如窗體名稱、當前登陸的用戶名等。初次調(diào)用一個DLL窗體實例時使用此函數(shù)創(chuàng)建。 FreeDLLForm 該函數(shù)將顯示釋放DLL窗口實例,在退出應用程序時調(diào)用每個DLL窗體的FreeDL

4、LForm方法來釋放創(chuàng)建的實例,不然會引起內(nèi)存只讀錯誤。同樣,也可以將一些在釋放窗體時需要做的業(yè)務(wù)邏輯用參數(shù)的形式傳遞給DLL窗體。 2.3 調(diào)試方式 DLL窗體程序無法直接執(zhí)行,需要有一個插件容器來調(diào)用。應此我們需要先實現(xiàn)一個基本的Hall程序,然后將Hall.exe保存在一個固定的目錄中。對每個DLL工程做如下設(shè)置: 1.        打開DLL工程 2.        選擇菜單 Run Parameters 3.      &#

5、160; 在彈出的窗口中瀏覽到我們的容器Hall.exe這樣在調(diào)試DLL程序時將會自動調(diào)用Hall程序,利用Hall中預留的調(diào)用接口調(diào)試DLL程序。 3 插件程序的基本實現(xiàn) DLL程序的設(shè)計方式和普通WINAPP沒有很大的區(qū)別,只是所有的窗口都是作為一種特殊的“資源”保存在DLL庫中,需要手動調(diào)用,而不像WINAPP中會有工程自動創(chuàng)建。聲明接口函數(shù)的方法很簡單 1.      在Unit的Implementation部分中聲明函數(shù) 2.      在函數(shù)聲明語句的尾部加上stdcall標記 3. 

6、;     在工程代碼(Project View Source)的begin語句之前,用exports語句聲明函數(shù)接口 為了使代碼簡潔,我個人喜歡在工程中獨立添加一個Unit單元(File New - Unit),然后將所有要輸出的函數(shù)體定義在此單元中,不要忘記將引用到的窗體的Unit也uses進來。我命名這個單元為UnitEntrance,在ShowDLLForm函數(shù)中初始化了要顯示的窗口并調(diào)用Show方法顯示,HALL會將登陸的用戶名用參數(shù)傳遞過來,得到用戶名后就可以進行一些權(quán)限控制,表現(xiàn)在界面初始化上。 其代碼如下 unit UnitOfficeEntran

7、ce;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms;function ShowDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;stdcall;function FreeDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;stdcall;implementationuses

8、 UnitOfficialMainForm;                / 改成MAINFORM的unitvar    DLL_Form:TFormOfficialMain;      /改成MAINFORM的NAME/-/Name: ShowDLLForm/Func: DLL插件調(diào)用入口函數(shù)/Para: AHandle 掛靠程序句柄; ACaption 本窗體標題/Rtrn: N/A/Auth: CST/Date: 2005-6-

9、3/-function ShowDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;begin    result:=true;    try        Application.Handle:=AHandle;    /掛靠到主程序容器        DLL_Form:=TFormOfficialMain.Create(Appl

10、ication);  /改成MAINFORM的NAME        try            with DLL_Form do            begin                Caption := ACaption;  

11、0;             StatusBar.Panels.Items0.Text := AUserID;                /Configure UI                Show ;            en

12、d;        except            on e:exception do            begin                dll_form.Free;           &#

13、160;end;        end;    except        result:=false;    end;end;/-/Name: FreeDLLForm/Func: DLL插件調(diào)用出口函數(shù)/Para: AHandle 掛靠程序句柄/Rtrn: true/false/-function FreeDLLForm(AHandle: THandle; ACaption: string; AUserID: string):bool

14、ean;begin    Application.Handle:=AHandle;    /掛靠到主程序容器    if DLL_Form.Showing then DLL_Form.Close;  /如果窗口打開先關(guān)閉,觸發(fā)FORM.CLOSEQUERY可取消關(guān)閉過程    if not DLL_Form.Showing then        begin         &

15、#160;  DLL_Form.Free;            result:=true;        end                               /仍然打開狀態(tài),說明CLOSEQUERY.CANCLOSE=FA

16、LSE    else        begin            result:=false;        end;end;end.DLL工程文件代碼如下: library Official;uses  SysUtils,  Classes,  UnitOfficialDetailForm in 'Un

17、itOfficialDetailForm.pas' FormOfficialDetail,  UnitOfficialMainForm in 'UnitOfficialMainForm.pas' FormOfficialMain,  UnitOfficeEntrance in 'UnitOfficeEntrance.pas',  UnitOfficialClass in '.PublicLibraryUnitOfficialClass.pas',  UnitM

18、yDataAdatper in '.PublicLibraryUnitMyDataAdatper.pas',  UnitMyHeaders in '.PublicLibraryUnitMyHeaders.pas'$R *.resexports ShowDLLForm,FreeDLLForm; /接口函數(shù)beginend.插件程序一旦調(diào)用了DLL窗口,窗口實例將會保持在HALL窗口的上層,因此不用擔心遮擋的問題。 4 容器程序的實現(xiàn)。 4.1 接口函數(shù)的引入 調(diào)用DLL庫中的函數(shù)有顯式和隱式兩種方式,顯式調(diào)用更靈活,因此我們使用顯示調(diào)用。在De

19、lphi中需要為接口函數(shù)申明函數(shù)類型,然后實例化函數(shù)類型的實例,該實例實際是一個指向函數(shù)的指針,通過指針我們可以訪問到函數(shù)并傳遞參數(shù)、獲取返回值。在單元文件的Interface部分加入函數(shù)類的申明: type    /定義接口函數(shù)類型,接口函數(shù)來自DLL接口TShowDLLForm = Function(AHandle:THandle; ACaption: String; AUserID:string):Boolean;stdcall;TFreeDLLForm = Function(AHandle:THandle; ACaption: String; AUserID:str

20、ing):boolean;stdcall;顯示調(diào)用庫函數(shù)需要如下幾個步驟 1.        載入DLL庫文件 2.        獲得函數(shù)地址 3.        執(zhí)行函數(shù) 4.        釋放DLL庫 接下來我們將詳細討論這幾個步驟。 4.2    載入DLL庫文件 通過調(diào)用API函數(shù)LoadLibrary可以將DLL庫載入到內(nèi)存

21、中,在此我們不討論DLL對內(nèi)存管理的影響。LoadLibrary的參數(shù)是DLL文件的地址路徑,如果載入成功會返回一個CARDINAL類型的變量作為DLL庫的句柄;如果目標文件不存在或其他原因?qū)е螺d入DLL文件失敗會返回一個0。 4.3    實例化接口函數(shù) 獲得接口函數(shù)指針的API函數(shù)為GetProcAddress(庫文件句柄,函數(shù)名稱),如果找到函數(shù)則會返回該函數(shù)的指針,如果失敗則返回NIL。 使用上文定義的函數(shù)類型定義函數(shù)指針變量,然后使用操作符獲得函數(shù)地址,這樣就可以使用指針變量訪問函數(shù)。主要代碼如下: var    ShowDLLForm: TS

22、howDLLForm;      /DLL接口函數(shù)實例    FreeDLLForm: TFreeDLLForm;begin    try        begin            APlugin.ProcAddr := LoadLibrary(PChar(sPath);            

23、;APlugin.FuncFreeAddr := GetProcAddress(APlugin.ProcAddr,'FreeDLLForm');            APlugin.FuncAddr := GetProcAddress(APlugin.ProcAddr ,'ShowDLLForm');            ShowDLLForm:=APlugin.FuncAddr ;  &#

24、160;         FreeDLLForm:=APlugin.FuncFreeAddr;            if ShowDllForm(Self.Handle, APlugin.Caption , APlugin.UserID)  then                Result:=True4.4   

25、 一個具體的實現(xiàn)方法 為了結(jié)構(gòu)化管理插件,方便今后的系統(tǒng)擴充,我們可以結(jié)合數(shù)據(jù)庫記錄可用的DLL信息,然后通過查詢數(shù)據(jù)庫記錄動態(tài)訪問DLL程序。 4.4.1        系統(tǒng)模塊表設(shè)計 對于MIS系統(tǒng),可以利用已有的DBS條件建立一個系統(tǒng)模塊表,記錄DLL文件及映射到系統(tǒng)模塊中的相關(guān)信息 字段名 作用 類型 AutoID 索引 INT modAlias 模塊別稱 VARCHAR modName 模塊名稱 VARCHAR modWndClass 窗體唯一標識 VARCHAR modFile DLL路徑 VARCHAR modMemo

26、備注 TEXT  模塊別稱是用來在編程設(shè)計階段統(tǒng)一命名的規(guī)則,特別是團隊開發(fā)時可以供隊員參考。  模塊名稱將作為ACAPTION參數(shù)傳遞給SHOWDLLFORM函數(shù)作為DLL窗口的標題。  窗體唯一標識是DLL子模塊中主窗口的CLASSNAME,用來在運行時確定要控制的窗口。  DLL路徑保存DLL文件名稱,程序中將轉(zhuǎn)換為絕對路徑。 4.4.2        插件信息數(shù)據(jù)結(jié)構(gòu) 定義一個記錄插件相關(guān)信息的數(shù)據(jù)接口可以集中控制DLL插件。在Interface部分加入如下代碼: type 

27、  /定義插件信息類    TMyPlugins = class        Caption:String;            /DLL窗體標題        DllFileName:String;        /DLL文件路徑        

28、;WndClass:String;           /窗體標識        UserID:string;             /用戶名        ProcAddr:THandle;          /LOADLIBRARY載入的庫句柄 

29、;       FuncAddrointer;          /SHOWDLLFORM函數(shù)指針        FuncFreeAddrointer;      /FREEDLLFORM函數(shù)指針    end;為每個插件創(chuàng)建一個TMyPlugins的實例,下文會討論對這些實例的初始化方法。 4.4.3       &

30、#160;插件載入函數(shù) 在本示例中DLL窗口是在HALL中觸發(fā)打開子窗口的事件中載入并顯示的。按鈕事件觸發(fā)后,先根據(jù)插件結(jié)構(gòu)體實例判斷DLL是否已經(jīng)加載,如果已經(jīng)加載,則控制窗口的顯示或關(guān)閉;如果沒有加載則訪問數(shù)據(jù)表將字段賦值到插件結(jié)構(gòu)體中,然后執(zhí)行載入、獲得指針的工作。 局部代碼如下 /-/Name: OpenPlugin/Func: 插件信息類控制過程: 初始化設(shè)置權(quán)限載入DLL窗口/Para: APlugin-TMyPlugins; sAlias別名; iFuncValue權(quán)限值/Rtrn: N/A/-procedure TFormHall.OpenPlugin(AFromActn: T

31、Action ;APlugin:TMyPlugins; sAlias:string; sUserID:string);var hWndPlugin:HWnd;begin    /判斷插件窗口是否已經(jīng)載入    hWndPlugin:=FindWindow(PChar(APlugin.WndClass),nil);    if hWndPlugin <> 0 then         /插件窗口已經(jīng)載入    begin   

32、     if not IsWindowVisible(hWndPlugin) then            begin                AFromActn.Checked := True;                ShowWindow(hWndPlugin

33、,SW_SHOWDEFAULT);   /顯示            end        else            begin                AFromActn.checked := False;    

34、           ShowWindow(hWndPlugin,SW_HIDE) ;            end;        Exit;                            

35、       /離開創(chuàng)建插件過程    end;     /初始化插件類實例    if not InitializeMyPlugins(APlugin,sAlias) then    begin        showmessage('初始化插件類錯誤。');        exit;    end; 

36、;   /獲得當前權(quán)限值    APlugin.UserID := sUserID;    /載入DLL窗口    if not LoadShowPluginForm(APlugin) then    begin        showmessage('載入中心插件出錯。');        exit;    end;end;/-/Name: Init

37、ializeMyPlugins/Func: 初始化MYPLUGIN實例  (Caption | DllFileName | IsLoaded)/Para: APlugin-TMyPlugins/Rtrn: N/A/-function TFormHall.InitializeMyPlugins(APlugin:TMyPlugins; sAlias:String):Boolean;var    strSQL:string;    myDA:TMyDataAdapter;begin    Result:=False;&#

38、160;   myDA:=TMyDataAdapter.Create;    strSQL:='SELECT * FROM SystemModuleList WHERE modAlias='+QuotedStr(sAlias);try        myDA.RetrieveData(strSQL);    except        on E:Exception do     &

39、#160;  begin            result:=false;            myDA.Free ;            exit;        end;    end;try      

40、60; begin            with myDA.MyDataSet do            begin                if Not IsEmpty then                begi

41、n                    APlugin.Caption:=      FieldByName('modName').Value;                    APlugin.DllFileName := FieldByName('

42、;modFile').Value;                    APlugin.WndClass :=    FieldByName('modWndClass').Value ;                    result:=True;  

43、0;             end;                Close;            end;    /end of with.do.        end;    /end of try    ex

44、cept        on E:Exception do        begin            Result:=False;            myDA.Free ;            Exit;   

45、;     end;    /end of exception    end;    /end of try.except    myDA.Free ;    end;/-/Name: LoadShowPluginForm/Func: 載入DLL插件并顯示窗口/Para: APlugin-TMyPlugins/Rtrn: true-創(chuàng)建成功/-function  TFormHall.LoadShowPluginForm (const A

46、Plugin:TMyPlugins):boolean;var    ShowDLLForm: TShowDLLForm;      /DLL接口函數(shù)實例    FreeDLLForm: TFreeDLLForm;    sPath:string;                   /DLL文件的完整路徑begin    try   &#

47、160;    begin            sPath:=ExtractFilepath(Application.ExeName)+ 'plugins' + APlugin.DllFileName ;            APlugin.ProcAddr := LoadLibrary(PChar(sPath);        

48、0;   APlugin.FuncFreeAddr := GetProcAddress(APlugin.ProcAddr,'FreeDLLForm');            APlugin.FuncAddr := GetProcAddress(APlugin.ProcAddr ,'ShowDLLForm');            ShowDLLForm:=APlugin.FuncAddr ;            FreeDLLForm:=APlugin.FuncFreeAddr;            if ShowDllForm(Self.Handle, APlugin.Capt

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論