如何動態使用 Package |
答題得分者是:jow
|
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
小弟目前製作了一個 package1,產生了 package1.bpl, package1.bpi, package1.lib
開一個新的專案 Project1,在 Form 裡面使用了 Package1 內的 Function AAA() 在 Project->Option->Packages 裡面,將 builder with runtime packages 打勾,並把 edit box 清空後,加入 package1.bpi 但是在編譯時,總是會有錯誤 [Linker Error] Unresolved external '__fastcall TForm1::AAA()' referenced from D:\BCB練習區\PACKAGE練習\U_MAIN.OBJ 除非把 Package1.lib 加入才不會有錯誤 因為想要使用動態載入 package 的方式,也就是執行時,會去連結 package1.bpl,如果沒有這個檔案就會錯誤。如果 package1.bpl 有更動,只要抽換掉即可,不需要將主程式重新編譯 那小弟的問題是,在上面的步驟中,必須加入 package1.lib,程式才能運作,那這不是變成靜態載入的方式了嗎?抽換掉 package1.bpl 還是沒用的,還是必須重新編譯才行 因此要如何做才能像 DLL 一樣,只要抽換掉 *.bpl 就可以,而不需要重新編譯? |
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
你何不這樣思考『加入 lib 後,是否就無法更換 bpl?如果還是可以,那 project 加入 lib 對你來說,有什麼困難?』
你別太執著「動態」二字,如果編譯器,來對像是什麼都不知道,又如何編譯? 另外要注意: 1. 要加入的是 bpl (not lib) 2. 相關搜尋路徑,是否正確 3. 記得 using (即使是 BCB) ===================引 用 seeing 文 章=================== 小弟目前製作了一個 package1,產生了 package1.bpl, package1.bpi, package1.lib 開一個新的專案 Project1,在 Form 裡面使用了 Package1 內的 Function AAA() 在 Project->Option->Packages 裡面,將 builder with runtime packages 打勾,並把 edit box 清空後,加入 package1.bpi 但是在編譯時,總是會有錯誤 [Linker Error] Unresolved external '__fastcall TForm1::AAA()' referenced from D:\BCB練習區\PACKAGE練習\U_MAIN.OBJ 除非把 Package1.lib 加入才不會有錯誤 因為想要使用動態載入 package 的方式,也就是執行時,會去連結 package1.bpl,如果沒有這個檔案就會錯誤。如果 package1.bpl 有更動,只要抽換掉即可,不需要將主程式重新編譯 那小弟的問題是,在上面的步驟中,必須加入 package1.lib,程式才能運作,那這不是變成靜態載入的方式了嗎?抽換掉 package1.bpl 還是沒用的,還是必須重新編譯才行 因此要如何做才能像 DLL 一樣,只要抽換掉 *.bpl 就可以,而不需要重新編譯? |
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
您好:
加入 lib 後,更換 bpl 是無效的,還是必須把程式重新編譯才行 1. 程式中有加入 bpl,但也必須要加入lib,否則無法 link,這點很奇怪 2.3. 都已經確認過是正確的了 另外,編譯時,因為已經有using了,所以編譯器應該知道要編譯的對象是誰了吧 ===================引 用 syntax 文 章=================== 你何不這樣思考『加入 lib 後,是否就無法更換 bpl?如果還是可以,那 project 加入 lib 對你來說,有什麼困難?』 你別太執著「動態」二字,如果編譯器,來對像是什麼都不知道,又如何編譯? 另外要注意: 1. 要加入的是 bpl (not lib) 2. 相關搜尋路徑,是否正確 3. 記得 using (即使是 BCB) |
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
|
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
|
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
請參考這一篇
http://edn.embarcadero.com/article/27178 ===================引 用 seeing 文 章=================== 您好,因為還要對VCL元件做更動,所以才考慮用BPL的方式 ===================引 用 jow 文 章=================== 動態載入DLL? 以下的function,是否都有用到? LoadLibrary() GetProcAddress() FreeLibrary() 另外,BPL的結構不同於一般的DLL ... 個人看法,僅供參考 |
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
必須要加入lib,否則無法 link,這點很奇怪 <--- 的確
jow 提供的 請參考這一篇 http://edn.embarcadero.com/article/27178 說得很清楚 另外我所指的加入 bpl,是加入在 Requires,凡是放在 Contains 的,都會重新編譯,而不只是「參考」 ===================引 用 seeing 文 章=================== 您好: 加入 lib 後,更換 bpl 是無效的,還是必須把程式重新編譯才行 1. 程式中有加入 bpl,但也必須要加入lib,否則無法 link,這點很奇怪 2.3. 都已經確認過是正確的了 另外,編譯時,因為已經有using了,所以編譯器應該知道要編譯的對象是誰了吧 ===================引 用 syntax 文 章=================== 你何不這樣思考『加入 lib 後,是否就無法更換 bpl?如果還是可以,那 project 加入 lib 對你來說,有什麼困難?』 你別太執著「動態」二字,如果編譯器,來對像是什麼都不知道,又如何編譯? 另外要注意: 1. 要加入的是 bpl (not lib) 2. 相關搜尋路徑,是否正確 3. 記得 using (即使是 BCB) |
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
|
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
解決了!
小弟後來想到用物件的方式來做
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
安裝了恭喜你找到 6 種動態載入的方法之一
自己試過一次,必了然於胸 ===================引 用 seeing 文 章=================== 解決了! 小弟後來想到用物件的方式來做
|
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
不過還是有問題,我的物件是繼承自 TComponent,一般 function 都沒事,只要一宣告 Graphics::TBitmap,在使用時,就一定會出錯 Access violation at address 7C93B21A in module 'ntdll.dll' Write of address 00000010。物件內的程式為
[code cpp] *.h #ifndef Component1H #define Component1H //--------------------------------------------------------------------------- #include #include #include //--------------------------------------------------------------------------- class PACKAGE TComponent1 : public TComponent { private: Graphics::TBitmap *Bmp; protected: public: __fastcall TComponent1(TComponent* Owner); __published: }; //--------------------------------------------------------------------------- #endif *.cpp #include <basepch.h><br /> #pragma hdrstop #include "Component1.h" #pragma package(smart_init) //--------------------------------------------------------------------------- // ValidCtrCheck is used to assure that the components created do not have // any pure virtual functions. // static inline void ValidCtrCheck(TComponent1 *) { new TComponent1(NULL); } //--------------------------------------------------------------------------- __fastcall TComponent1::TComponent1(TComponent* Owner) : TComponent(Owner) { Bmp = new Graphics::TBitmap; Bmp->PixelFormat = pf24bit; } //--------------------------------------------------------------------------- namespace Component1 { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(TComponent1)}; RegisterComponents("Test", classes, 0); } } //--------------------------------------------------------------------------- [/code] 只要這樣就死了,這是沒有安裝物件的方式;如果將物件安裝上去,並且取消 builder with runtime packages,這樣又沒事,不知道是哪邊沒做好嗎? 完整程式如下: 4b15cc57c9287_Test1.zip
編輯記錄
seeing 重新編輯於 2009-12-02 10:17:40, 註解 無‧
|
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
用D6寫的範例, 提供你參考
http://delphi.ktop.com.tw/download.php?download=upload/4b166e6da351f_TEST12.zip 專案群組 PRG12.BPG 中內含三個專案 a. TYPE12.BPL(內含 fTypeDef.pas) b. BPL12.BPL(內含 fFunc2.pas: TForm2) c. TEST12.EXE(內含 fMain.pas: TForm1) TYPE12.BPL: (1)宣告一些function type (2)自訂虛擬抽象類別, TMyBaseComponent (3)定義一些公用變數 (4)這個BPL提供給 TEST12.EXE 和 BPL12.BPL 靜態載入使用 也就是說, TEST12.EXE 和 BPL12.BPL 專案中 都有 BPL12.BPL: (1)TMyComponent 繼承並改寫 TMyBaseComponent 為求精簡, 實作程式碼也寫在 fFunc2.pas 中 (2)自訂類別 TForm2 (3)這個BPL提供給 TEST12.EXE 動態載入使用 也就是說, TEST12.EXE 專案中, 不會有 TYPE12.BPL [code delphi] unit fTypeDef; interface uses Windows, Classes, Dialogs, SysUtils, Graphics; type TMethod1 = function: string of object; TMethod2 = function(S: string): string of object; TMethod3 = function(const FileName: string; var Bitmap: TBitmap): Boolean of object; TMethod4 = procedure(c: TCanvas; r: TRect; b: TBitmap) of object; TMyBaseComponent = class(TComponent) public function Method1: string; virtual; abstract; function Method2(S: string): string; virtual; abstract; function Method3(const FileName: string; var Bitmap: TBitmap): Boolean; virtual; abstract; procedure Method4(c: TCanvas; r: TRect; b: TBitmap); virtual; abstract; end; TMyBaseComponentClass = class of TMyBaseComponent; { Public Function } function FindMethod(Obj: TObject; MethodName: string; var TheMethod: TMethod): Boolean; function GetBitmap(const FileName: string; var Bitmap: TBitmap): Boolean; function MyGetClass(LibName, ClsName: string; var h: HMODULE; var AClass: TPersistentClass): Boolean; procedure DrawBitmep(c: TCanvas; r: TRect; b: TBitmap); implementation function FindMethod(Obj: TObject; MethodName: string; var TheMethod: TMethod): Boolean; begin Result := False; TheMethod.Code := Obj.MethodAddress(MethodName); if Assigned(TheMethod.Code) then begin Result := True; TheMethod.Data := Pointer(Obj); end; end; function GetBitmap(const FileName: string; var Bitmap: TBitmap): Boolean; begin Bitmap := nil; if FileExists(FileName) then begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile(FileName); end; Result := Bitmap <> nil; end; function MyGetClass(LibName, ClsName: string; var h: HMODULE; var AClass: TPersistentClass): Boolean; begin h := 0; AClass := nil; if not FileExists(LibName) then ShowMessage('Library not found: ' LibName) else begin h := LoadPackage(LibName); if h = 0 then ShowMessage('LoadPackage Failure: ' LibName) else AClass := GetClass(ClsName); end; Result := AClass <> nil; if not Result and (h<>0) then begin UnloadPackage(h); end; end; procedure DrawBitmep(c: TCanvas; r: TRect; b: TBitmap); begin if b <> nil then begin c.Lock; try c.StretchDraw(r,b); finally c.Unlock; end; end; end; end. [/code] TEST12.EXE [code delphi] unit fMain; interface uses Windows, SysUtils, Classes, Graphics, Controls, Dialogs, Forms, StdCtrls, fTypeDef; type TForm1 = class(TForm) btnUseForm2: TButton; btnUseMyComponent: TButton; procedure btnUseForm2Click(Sender: TObject); procedure btnUseMyComponentClick(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.btnUseMyComponentClick(Sender: TObject); var h: HMODULE; AClass: TPersistentClass; O: TMyBaseComponent; b: TBitmap; rt: TRect; begin if MyGetClass('BPL12.BPL','TMyComponent',h,AClass) then try O := TMyBaseComponentClass(AClass).Create(Self); try O.Method1; O.Method2('0123456789'); if O.Method3('BACK1.BMP',b) then try rt := Rect(0,0,b.Width,b.Height); OffsetRect(rt, 5, 5); O.Method4(Canvas,rt,b); finally FreeAndNil(b); end; finally FreeAndNil(O); end; finally UnLoadPackage(h); end; end; procedure TForm1.btnUseForm2Click(Sender: TObject); var h: HMODULE; AClass: TFormClass; F: TForm; m: TMethod; b: TBitmap; rt: TRect; begin if MyGetClass('BPL12.BPL','TForm2',h,TPersistentClass(AClass)) then try F := AClass.Create(Self); try if FindMethod(F,'Method1',m) then TMethod1(m); if FindMethod(F,'Method2',m) then TMethod2(m)('0123456789'); if FindMethod(F,'Method3',m) and TMethod3(m)('BACK1.BMP',b) then try if FindMethod(F,'Method4',m) then begin rt := Rect(0,0,b.Width,b.Height); OffsetRect(rt,b.Width 10, 5); TMethod4(m)(Canvas,rt,b); end; finally FreeAndNil(b); end; F.ShowModal; finally FreeAndNil(F); end; finally UnLoadPackage(h); end; end; end. [/code] |
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
小弟後來用物件的方式來做
Dear Jow, 您的程式小弟會再仔細研讀的,謝謝您 |
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
哈, 我果然想太多了!
雖然花了一點時間實作 我還是認為這是一個很有趣的應用... 觀念上,以下的方式還是一種靜態引用 LoadPackage(), UnLoadPackage() 應該用不上吧 因為 以下的第三點所提到在 雖然是builder with runtime packages 因為類別資訊與實作碼在同一個BPL中 應用程式執行時便會自動載入BPL檔 我的做法是: 在TYPE12.BPL中宣告一個虛擬抽象類別與其類別型態 TMyBaseComponentClass = class of TMyBaseComponent; 其下所有Method皆為虛擬抽象的(virtual; abstract;) 然後在BPL12.BPL 中 以TMyComponent 繼承實作 這種做法可以達到作應用程式中,同時使用任意數量的不同實作 可以是同一檔案中的不同實作 或是 跨越不同檔案的實作 並且只在需要時動態載入, 這部分端視應用程式如何去定義其 引用的動作 注意: MyGetClass() 傳入的參數LibName, ClsName 可以是讓應用程式以某種方式自行取得的 並且應用程式在編譯時,並不需要在 builder with runtime packages 的Edit Box 中 將BPL12.BPL 寫死在裡面 另外, 對於 TEST12.EXE 而言 TForm2 是一個完全未知的類別 其下所有的Method 也是以FindMethod() 動態取得的 總之, 隱約感覺這樣的寫法, 似乎可以達到 plug-in 的需求... 個人看法, 僅供參考 ===================引 用 seeing 文 章=================== 小弟後來用物件的方式來做
Dear Jow, 您的程式小弟會再仔細研讀的,謝謝您 |
seeing
初階會員 發表:49 回覆:131 積分:41 註冊:2002-11-07 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |