电竞比分网-中国电竞赛事及体育赛事平台

分享

無(wú)痛使用Delphi Package

 喜歡站在山上 2021-01-21

Package的優(yōu)點(diǎn)

  • 應(yīng)用程序可以被高度的模塊化,而且可以逐漸交付完成的功能給客戶(hù)
  • 維護(hù)方便,可以只更新單一的模塊功能
  • 提升程序的載入速度

Package的缺點(diǎn)

  • 有些情形下使用Package只能間接參考的方式取得資料(變量, 類(lèi) …).
  • Package Name 不能重復(fù).
  • Contains 中的 Unit Name 不能在所有的Package中重復(fù)出現(xiàn),只能出現(xiàn)一次
  • PackageA有使用到PackageB必需要在Requires中引用 但是PackageA及PackageB不能彼此循環(huán)引用.

Package種類(lèi)

當(dāng)用戶(hù)運(yùn)行應(yīng)用程序時(shí),運(yùn)行時(shí)程序包提供功能。 設(shè)計(jì)時(shí)程序包用于在IDE中安裝組件并為自定義組件創(chuàng)建特殊的屬性編輯器。 單個(gè)包可以在設(shè)計(jì)時(shí)和運(yùn)行時(shí)均起作用,并且設(shè)計(jì)時(shí)包經(jīng)常通過(guò)在其require子句中引用運(yùn)行時(shí)包來(lái)工作。

  • 設(shè)計(jì)期包(Designtime only) -用來(lái)在DELPHI的IDE環(huán)境安裝控件和為控件建立特殊的屬性編輯器。設(shè)計(jì)期包允許包含控件、屬性和控件編輯器等等,
  • 運(yùn)行期包(Runtime only)-當(dāng)運(yùn)行程序時(shí)提供VCL和庫(kù)函數(shù)的支持,操作上很類(lèi)似標(biāo)準(zhǔn)的動(dòng)態(tài)鏈接庫(kù)。Install按鈕無(wú)法使用。
  • 設(shè)計(jì)和運(yùn)行期包(Designtime and Runtime ):設(shè)計(jì)與運(yùn)行時(shí)都能用

無(wú)痛使用Delphi Package

Package文件說(shuō)明

BPL 英文全稱(chēng) Borland Package library ,是一種特殊的DLL文件,用于代碼重用和減少可執(zhí)行文件。編譯bpl時(shí),僅需要添加相應(yīng)功能的pas文件,如果有窗體,則需要添加dfm文件。既然是DLL文件,那就是在運(yùn)行時(shí)所需要的文件。BPL相當(dāng)于C++中的DLL

DCP 英文全稱(chēng):delphi compiled package,是 package 編譯時(shí)跟 bpl 一起產(chǎn)生出來(lái)的,記錄著 package 中公開(kāi)的 class、procedure、function、variable、const.... 等等的名稱(chēng)和相對(duì)位置。如果 某個(gè)控件包 A 引用了 控件包 B,當(dāng) 控件包 A 編譯時(shí),需要 控件包 B.dcp,若 控件包 B 有修改,更改了公開(kāi)的界面,則 控件包 A 必須在 控件包 B 編譯之后重新編譯,以引用新的 B.dcp。否則,當(dāng) 控件包 A 執(zhí)行時(shí),執(zhí)行到引用自 控件包 B 的內(nèi)容時(shí),就會(huì)出現(xiàn)錯(cuò)誤。DCP相當(dāng)于C++中的Lib,編譯時(shí)需要。

DCU 英文全稱(chēng):Delphi Compiled Unit File,是delphi單元文件.pas文件編譯后產(chǎn)生的文件,感覺(jué)沒(méi)有太大用處。

Package加載方式

Package中的代碼

unit Unit2;interfaceuses Vcl.Dialogs;//函數(shù)案例function add(Num1, Num2: Integer): Integer; stdcall;//過(guò)程案例procedure ShowMsg(Str: String); stdcall;type//類(lèi)的案例 TUser = class public function ShowString(): string; end; // 需要像DLL一樣聲明導(dǎo)出函數(shù)的列表,如果是靜態(tài)導(dǎo)入此項(xiàng)可以省略exports add, ShowMsg;implementationprocedure ShowMsg(Str: String);begin showmessage(Str);end;function add(Num1, Num2: Integer): Integer;begin Result := Num1 + Num2;end;{ TUser }function TUser.ShowString: string;begin Result := 'HelloWorld';end;end.

靜態(tài)加載

一般大家在用Delphi時(shí)都是使用『靜態(tài)載入』, 像VCL的Package就是這種方式, 這種方式的好處是設(shè)計(jì)者不用去理會(huì)Package 的載入和釋放, 其實(shí)設(shè)計(jì)者根本感覺(jué)不到設(shè)用這項(xiàng)技術(shù); 當(dāng)然也可以手動(dòng)將Package加入到項(xiàng)目中『project->Options->Packages->Build with runtime packages中加入Package Name彼此的分隔符是分號(hào)』

無(wú)痛使用Delphi Package
無(wú)痛使用Delphi Package

動(dòng)態(tài)載入代碼

基本上是無(wú)痛使用,只要路徑配置沒(méi)有問(wèn)題,基本上和使用普通單元沒(méi)有區(qū)別

implementationuses  Unit2, Unit3;{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);begin  showmessage(TUser.create().showString());  var  From3 := TForm3.create(nil);  From3.visible := true;end;

動(dòng)態(tài)加載

動(dòng)態(tài)加載和靜態(tài)加載相反,無(wú)論是載入還是釋放都要自己來(lái)處理,看起來(lái)好像是動(dòng)態(tài)載入,這種方式個(gè)人感覺(jué)相當(dāng)麻煩,雖然本質(zhì)上和dll的動(dòng)態(tài)加載一樣,但是因?yàn)樵趯?dǎo)入的元素中多了類(lèi)的概念,所以還需要使用反射的方式創(chuàng)建類(lèi)的對(duì)象才能實(shí)現(xiàn)類(lèi)成員的引用

implementationuses rtti, System.StrUtils;{$R *.dfm}procedure TForm1.Button2Click(Sender: TObject);var // 聲明和Package導(dǎo)出列表中一致結(jié)構(gòu)的過(guò)程 add01: procedure(Msg: String); stdcall; // 聲明和Package導(dǎo)出列表中一致結(jié)構(gòu)的函數(shù) add02: function(Num1: Integer; Num2: Integer): Integer; stdcall;begin // 載入bpl格式的Package var PackageHandle := LoadPackage('Package1.bpl'); if PackageHandle <> 0 then begin // 載入成功之后獲取對(duì)應(yīng)函數(shù)、過(guò)程的指針 @add01 := GetProcAddress(PackageHandle, 'ShowMsg'); @add02 := GetProcAddress(PackageHandle, 'add'); if @add01 <> nil then begin // 調(diào)用 add01('HelloWorld'); showmessage(add02(1, 2).Tostring); end; end; // 對(duì)于類(lèi)我們需要先創(chuàng)建類(lèi)的對(duì)象然后才可以實(shí)現(xiàn)類(lèi)中函數(shù)的調(diào)用 var // 創(chuàng)建運(yùn)行期上下問(wèn)對(duì)象 rc := TRttiContext.create; var // 載入對(duì)應(yīng)單元中的類(lèi),注意此處需要寫(xiě)單元名+類(lèi)名 ClassType := rc.FindType('Unit2.TUser'); var // 獲取元類(lèi)實(shí)例(對(duì)象) Instance := ClassType.AsInstance; var // 獲取該實(shí)例的元信息類(lèi)型 QRClass := Instance.MetaclassType; var // 獲取用于創(chuàng)建TUser類(lèi)型的構(gòu)造方法 CreateMethod := Instance.GetMethod('Create'); var // 利用獲取到的構(gòu)造方法對(duì)象,創(chuàng)建TUser類(lèi)對(duì)象 User := CreateMethod.Invoke(QRClass, []); var // 函數(shù)調(diào)用 rs := ClassType.GetMethod('ShowString').Invoke(User, []); // 顯示返回值 showmessage(rs.asstring); //卸載包 UnloadPackage(PackageHandle);end;

從上面動(dòng)態(tài)加載的代碼可以看出涉及到反射相關(guān)的知識(shí),個(gè)人感覺(jué)這種方式在使用起來(lái)不太方便,當(dāng)然如果對(duì)反射比較熟悉的話那就沒(méi)問(wèn)題了

動(dòng)態(tài)載入?yún)⒖即a

我在搜索Package相關(guān)內(nèi)容的使用看到下面這段代碼,它也可以實(shí)現(xiàn)創(chuàng)建類(lèi)的對(duì)象,只是中間出現(xiàn)的類(lèi)型的強(qiáng)制轉(zhuǎn)換,個(gè)人不是特別推薦,只是記錄一下作為筆記參考

function CreateFormByClassName(ClassName: string): integer;var  AClass: TPersistentClass;  AForm: TCustomForm;begin  Result := mrNone;  AClass := GetClass(ClassName);  if AClass <> nil then  begin    AForm := TComponentClass(AClass).Create(Application) as TCustomForm;    Result := AForm.ShowModal;  end;

官方參考文檔

官方文檔是英文的,我也是翻看+翻譯讀了很久挑了幾篇有用的

  • http://docwiki./RADStudio/Sydney/en/Packages_(Delphi)
  • http://docwiki./RADStudio/Sydney/en/Compiling_Packages
  • http://docwiki./RADStudio/Sydney/en/Loading_Packages_in_an_Application
  • http://docwiki./RADStudio/Sydney/en/Add_Runtime_Package

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多