国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Delphi > 正文

Delphi 插件創(chuàng)建、調(diào)試與使用應(yīng)用程序擴(kuò)展

2019-11-17 05:09:24
字體:
供稿:網(wǎng)友

  有沒有使用過Adobe photoshop假如用過,你就會(huì)對(duì)插件的概念比較熟悉。對(duì)外行人來說,插件僅僅是從外部提供給應(yīng)用程序的代碼塊而已(舉個(gè)例子來說,在一個(gè)DLL中)。一個(gè)插件和一個(gè)普通DLL之間的差異在于插件具有擴(kuò)展父應(yīng)用程序功能的能力。
例如,Photoshop本身并不具備進(jìn)行大量的圖像處理功能。插件的加入使其獲得了產(chǎn)生諸如模糊、斑點(diǎn),以及其他所有風(fēng)格的希奇效果,而其中任何一項(xiàng)功能都不是父應(yīng)用程序自身所具有的。
  對(duì)于圖像處理程序來說這很不錯(cuò),可是為什么要花偌大的力氣去完成支持插件的商業(yè)應(yīng)用程序呢?假設(shè),我們舉個(gè)例子,你的應(yīng)用程序要產(chǎn)生一些報(bào)表。你的客戶肯定會(huì)一直要求更新或者增加新的報(bào)表。你可以使用一個(gè)諸如Report Smith的外部報(bào)表生成器,這是個(gè)不怎么樣的解決方案,需要發(fā)布附加的文件,要對(duì)用戶進(jìn)行額外的培訓(xùn),等等。你也可以使用QuickReport,不過這會(huì)使你身處版本控制的噩夢(mèng)之中——假如每改變一次字體你就要Rebuild你的應(yīng)用程序的話。
  然而,只要你把報(bào)表做到插件中,你就可以使用它。需要一個(gè)新的報(bào)表嗎?沒問題,只要安裝一個(gè)DLL,下次應(yīng)用程序啟動(dòng)時(shí)就會(huì)看見它了。另外一個(gè)例子是處理來自外部設(shè)備(比如條形碼掃描器)的數(shù)據(jù)的應(yīng)用程序,為了給用戶更多的選擇,你不得不支持半打的各種設(shè)備。通過將每種設(shè)備接口處理例程寫成插件,不用對(duì)父應(yīng)用程序作任何變動(dòng)就可以獲得最大程度的可伸縮性。

入門

  在開始寫代碼之前最重要的事情就是搞清楚你的應(yīng)用程序到底需要擴(kuò)展哪些功能。這是因?yàn)椴寮峭ㄟ^一個(gè)特定的接口與父應(yīng)用程序交互的,而這個(gè)接口將根據(jù)你的需要來定義。在本文中,我們將建立3個(gè)插件,以便展示插件與父應(yīng)用程序相交互的幾種方式。
  我們將把插件制作成DLL。不過,在做這項(xiàng)工作之前,我們得先制作一個(gè)外殼程序來載入和測試它們。圖1顯示的是加載了第一個(gè)插件以后的測試程序。第一個(gè)插件沒有完成什么大不了的功能,實(shí)際上,它所做的只是返回一個(gè)描述自己的字符串。不過,它證實(shí)了很重要的一點(diǎn)——不管有沒有插件應(yīng)用程序都可以正常運(yùn)行。假如沒有插件,它就不會(huì)出現(xiàn)在已安裝的插件列表中,但是應(yīng)用程序仍然可以正常的行使功能。

  我們的插件外殼程序與普通應(yīng)用程序之間的唯一不同就在于工程源文件中出現(xiàn)在uses子句中的Sharemem單元和加載插件文件的代碼。任何在自身與子DLL之間傳遞字符串參數(shù)的應(yīng)用? 都需要Sharemem單元,它是DelphiMM.dll(Delphi提供該文件)的接口。要測試這個(gè)外殼,需要將DelphiMM.dll文件從Delphi/Bin目錄復(fù)制到path環(huán)境變量所包含的路徑或者應(yīng)用程序所在目錄中。發(fā)布最終版本時(shí)也需要同時(shí)分發(fā)該文件。
插件通過LoadPlugins過程載入到這個(gè)測試外殼中,這個(gè)過程在主窗口的FormCreate事件中調(diào)用,見圖2。該過程使用FindFirst和FindNext函數(shù)在應(yīng)用程序所在目錄中查找插件文件。找到一個(gè)文件以后,就使用圖3所示的LoadPlugins過程將其載入。
{ 在應(yīng)用程序目錄下查找插件文件 }
PRocedure TfrmMain.LoadPlugins;
var
  sr: TSearchRec;
  path: string;
  Found: Integer;
begin
  path := ExtractFilePath(application.Exename);
  try
  Found := FindFirst(path + cPLUGIN_MASK, 0, sr);
  while Found = 0 do begin
  LoadPlugin(sr);
  Found := FindNext(sr);
end;
  finally
  FindClose(sr);
end;
end;


{ 加載指定的插件 DLL. }
procedure TfrmMain.LoadPlugin(sr: TSearchRec);
var
  Description: string;
  LibHandle: Integer;
  DescribeProc: TPluginDescribe;
begin
  LibHandle := LoadLibrary(Pchar(sr.Name));
  if LibHandle $#@60;$#@62; 0 then
begin
  DescribeProc := GetProcAddress(LibHandle, cPLUGIN_DESCRIBE);
if Assigned(DescribeProc) then

begin
 DescribeProc(Description);
 memPlugins.Lines.Add(Description);
end
else
begin
 MessageDlg(’File "’ + sr.Name +’" is not a valid plug-in.’,
mtInformation, [mbOK], 0);
end;
end
else
MessageDlg(’An error occurred loading the plug-in "’ +
sr.Name + ’".’, mtError, [mbOK], 0);
end;


  LoadPlugin方法展示了插件機(jī)制的核心。首先,插件被寫成DLL。其次,通過LoadLibrary API它被動(dòng)態(tài)的加載。一旦DLL被加載,我們就需要一個(gè)訪問它所包含的過程和函數(shù)的途徑。API調(diào)用GetProcAddress提供這種機(jī)制,它返回一個(gè)指向所需例程的指針。在我們這個(gè)簡單的演示中,插件僅僅包含一個(gè)名為DescribePlugin的過程,由常數(shù)cPLUGIN_DESCRIBE指定(過程名的大小寫非常重要,傳遞到GetProcAddress的名稱必須與包含在DLL中的例程名稱完全一致)。假如在DLL中沒有找到請(qǐng)求的例程,GetProcAddree將返回nil,這樣就答應(yīng)使用Assigned函數(shù)測定返回值。
  為了以一種易用的方式存儲(chǔ)指向一個(gè)函數(shù)的指針,有必要為用到的變量創(chuàng)建一個(gè)特定的類型。注重,GetProcAddress的返回值被存儲(chǔ)在一個(gè)變量中,DescribeProc,屬于TpluginDescribe類型。下面是它的聲明:
type
TPluginDescribe = procedure(var Desc: string); stdcall;
  由于過程存在于DLL內(nèi)部,它通過標(biāo)準(zhǔn)調(diào)用轉(zhuǎn)換編譯所有導(dǎo)出例程,因此需要使用stdcall指示字。這個(gè)過程使用一個(gè)var參數(shù),當(dāng)過程返回的時(shí)候它包含插件的描述。
  要調(diào)用剛剛獲得的過程,只需要使用保存地址的變量作為過程名,后面跟上任何參數(shù)。就我們的例子而言,聲明:
DescribeProc(Description)
  將會(huì)調(diào)用在插件中獲得的描述過程,并且用描述插件功能的字符串填充Description變量。

構(gòu)造插件

  我們已經(jīng)創(chuàng)建好了父應(yīng)用程序,現(xiàn)在該輪到創(chuàng)建我們希望加載的插件了。插件文件是一個(gè)標(biāo)準(zhǔn)的Delphi DLL,所以我們從Delphi IDE中創(chuàng)建一個(gè)新DLL工程,保存它。由于導(dǎo)出的插件函數(shù)將用到字符串參數(shù),所以要在工程的uses子句中把Sharemen單元放在最前面。圖4列出的就是我們這個(gè)簡單插件的工程源文件。
uses
Sharemem, SysUtils, Classes,
main in ’main.pas’;

{$E plg.}

eXPorts
DescribePlugin;

begin

end.


  雖然插件是一個(gè)DLL文件,但是沒有必要一定要給它一個(gè).DLL的擴(kuò)展名。實(shí)際上,一個(gè)原因就足以讓我們有理由改變擴(kuò)展名:當(dāng)父應(yīng)用程序?qū)ふ乙虞d的文件時(shí),新的擴(kuò)展名可以作為特定的文件掩模。通過使用別的擴(kuò)展名(我們的例子使用了*.plg),你可以在一定程度上確信應(yīng)用程序只會(huì)載入相應(yīng)的文件。編譯指示字$X可以實(shí)現(xiàn)這個(gè)改變,也可以通過Project Options對(duì)話框的Application頁來設(shè)置擴(kuò)展名。
  第一個(gè)例子插件的代碼是很簡單的。圖5顯示了包含在一個(gè)新單元中的代碼。注重,DescribePlugin原型與外殼應(yīng)用程序中的TpluginDescribe類型相一致,使用附加的export保留字指定該過程將被導(dǎo)出。被導(dǎo)出的過程名稱也將會(huì)出現(xiàn)在主工程源代碼的exports段中(在圖4中列出)。
unit main;

interface

procedure DescribePlugin(var Desc: string);
export; stdcall;

implementation

procedure DescribePlugin(var Desc: string);
begin
Desc := ’Test plugin v1.00’;
end;

end.


  在測試這個(gè)插件之前,要先把它復(fù)制到主應(yīng)用程序的路徑下。最簡單的辦法就是在主目錄的子目錄下創(chuàng)建插件,然后把輸出路徑設(shè)置為主路徑(Project Options對(duì)話框的Directories/Conditionals也可以作這個(gè)設(shè)置)。

調(diào)試

  現(xiàn)在介紹一下Delphi 3中一個(gè)較好的功能:從IDE中調(diào)試DLL的能力。在DLL工程中可以通過Run paramaters對(duì)話框指定某程序?yàn)樗拗鲬?yīng)用程序,這就是指向?qū)⒄{(diào)用DLL的應(yīng)用程序的路徑(在我們這個(gè)例子中,就是剛剛創(chuàng)建的測試外殼程序)。然后你就可以在DLL代碼中設(shè)置斷點(diǎn)并且按F9運(yùn)行它——就像在一個(gè)普通應(yīng)用程序中做的那樣。Delphi會(huì)運(yùn)行指定的宿主程序,并且,通過編譯帶有調(diào)試信息的DLL,把你指引到DLL代碼內(nèi)的斷點(diǎn)處。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 孟连| 资源县| 怀柔区| 从化市| 承德县| 资溪县| 乌拉特中旗| 双峰县| 邮箱| 绥中县| 公安县| 改则县| 乐亭县| 贺兰县| 吴忠市| 湟中县| 阿巴嘎旗| 惠安县| 繁峙县| 汶川县| 清河县| 揭东县| 卓资县| 巴楚县| 达孜县| 甘孜| 共和县| 长丰县| 昌平区| 乡宁县| 丰镇市| 两当县| 乌什县| 仁怀市| 夹江县| 射洪县| 湖北省| 台东市| 邳州市| 闽侯县| 崇明县|