C++ Builder 參考手冊(cè) ? 創(chuàng)建和使用動(dòng)態(tài)加載的包 (.bpl)
- 動(dòng)態(tài)加載的包 (.bpl) 簡(jiǎn)介
- 創(chuàng)建一個(gè)動(dòng)態(tài)加載的包 (.bpl)
- 使用動(dòng)態(tài)加載的包 (.bpl)
1. 動(dòng)態(tài)加載的包 (.bpl) 簡(jiǎn)介
組件包文件 .bpl 不安裝在控件面板上,不通過(guò)拖拽放置在 Form 上仗嗦,也沒(méi)有頭文件的情況下阱飘,只有一個(gè) .bpl 文件长搀,通過(guò) LoadPackage 加載靖避,然后使用里面的函數(shù)和類。C++ 沒(méi)有原生支持的反射屯断,不像 Delphi 直接通過(guò)類名反射出對(duì)象昨稼,但是仍然有辦法創(chuàng)建和使用動(dòng)態(tài)加載的包:
- 動(dòng)態(tài)加載的 bpl 文件里面要有創(chuàng)建類的函數(shù),并且按照 dll 函數(shù)導(dǎo)出论皆;
? Delphi 只需要知道類名就可以使用了益楼;
? C++ 類名沒(méi)有用,需要知道創(chuàng)建類的對(duì)象的函數(shù)名点晴; - 只要?jiǎng)?chuàng)建了對(duì)象感凤,通過(guò)對(duì)象指針可以枚舉屬性、事件和方法粒督;
- 通過(guò)成員函數(shù)名 (字符串) 可以調(diào)用成員函數(shù)陪竿。
2. 創(chuàng)建一個(gè)動(dòng)態(tài)加載的包 (.bpl)
2.1. 創(chuàng)建組件包項(xiàng)目
和普通的組件包一樣:
選擇菜單 File -> New -> Package - C++ Builder
或者菜單 File -> New - Other... 在打開(kāi)的對(duì)話框里面,左面的樹形結(jié)構(gòu)選擇 C++ Builder屠橄,右面選擇 Package
創(chuàng)建一個(gè) .bpl 組件包項(xiàng)目
2.2. 添加組件
和普通的組件包一樣:
選擇菜單 Component -> New Component
選擇 VCL for C++ Win32 添加一個(gè) VCL 組件族跛,然后選擇從哪個(gè)類繼承,運(yùn)行時(shí)不可見(jiàn)的組件仇矾,可以選擇 TComponent 作為父類庸蔼,也可以根據(jù)需要選擇其他的類作為父類。
然后:
選擇安裝在組件面板上的哪個(gè)頁(yè)面贮匕,也可以自己起個(gè)名字姐仅;
生成的源程序存放位置和文件名;
類的 __published 訪問(wèn)權(quán)限的屬性刻盐、事件和方法支持通過(guò)對(duì)象指針枚舉和通過(guò)名稱 (字符串) 訪問(wèn)掏膏。
2.3. 添加其他類
所有從 TObject 繼承的類的 __published 訪問(wèn)權(quán)限的成員都支持枚舉屬性、事件和方法敦锌,也支持通過(guò)成員函數(shù)名調(diào)用成員函數(shù)馒疹,只要給類加上 PACKAGE 屬性就可以從組件包里面導(dǎo)出,在組件包外面調(diào)用乙墙,例如:class PACKAGE THsuanluTest : public TObject { ...
2.4. 添加創(chuàng)建類的函數(shù)
創(chuàng)建類的函數(shù)必須定義為 C 語(yǔ)言格式 (extern "C") 和 __stdcall 調(diào)用約定颖变,并且也需要指定 PACKAGE 屬性從包里面導(dǎo)出這個(gè)函數(shù)。
例:通過(guò)菜單 Component -> New Component 創(chuàng)建的繼承 TComponent 的類 THsuanluComponent1听想,寫個(gè)函數(shù) CreateComponent1 創(chuàng)建 THsuanluComponent1 類:
extern "C" TObject *PACKAGE __stdcall CreateComponent1(void)
{
return new THsuanluComponent1(NULL);
}
3. 使用動(dòng)態(tài)加載的包 (.bpl)
- 使用 LoadPackage 加載 .bpl
- 使用 GetProcAddress 通過(guò)函數(shù)名字符串獲取創(chuàng)建類的函數(shù)腥刹,例如前面說(shuō)的 CreateComponent1 函數(shù),然后調(diào)用這個(gè)函數(shù)創(chuàng)建類汉买,得到 TObject 對(duì)象指針衔峰;
- 通過(guò) TObject 指針可以枚舉所有的屬性、事件和方法;
- 通過(guò) TObject 指針調(diào)用 MethodAddress 方法垫卤,可以通過(guò)成員函數(shù)名字符串獲取成員函數(shù)的地址威彰,然后通過(guò) TObject 指針和成員函數(shù)地址合成 __closure 指針,調(diào)用這個(gè) __closure 指針即調(diào)用了這個(gè)對(duì)象的成員函數(shù)穴肘。
例子:
創(chuàng)建 HsuanluTestPackage.bpl 包:
- 選擇菜單 File -> New -> Package - C++ Builder 創(chuàng)建一個(gè) .bpl 組件包項(xiàng)目
- 選擇菜單 Component -> New Component歇盼,然后選擇 VCL for C++ Win32 添加一個(gè) VCL 組件,選擇 TComponent 作為父類评抚,類名為 THsuanluComponent1
- 在生成的類里面添加 __published: 成員 void TestFunc(void);
以下為類的定義和實(shí)現(xiàn)部分旺遮、以及創(chuàng)建這個(gè)類的對(duì)象的函數(shù) CreateComponent1,其他部分省略
class PACKAGE THsuanluComponent1 : public TComponent
{
private:
protected:
public:
__fastcall THsuanluComponent1(TComponent* Owner);
__published:
void TestFunc(void);
};
__fastcall THsuanluComponent1::THsuanluComponent1(TComponent* Owner)
: TComponent(Owner)
{
}
//---------------------------------------------------------------------------
void THsuanluComponent1::TestFunc(void)
{
::MessageBox(NULL, L"測(cè)試組件包:THsuanluComponent1::TestFunc", L"TestFunc - 玄坴", MB_OK|MB_ICONINFORMATION);
}
//---------------------------------------------------------------------------
extern "C" TObject *PACKAGE __stdcall CreateComponent1(void)
{
return new THsuanluComponent1(NULL);
}
調(diào)用 HsuanluTestPackage.bpl 包:
這個(gè)例子的目標(biāo)是調(diào)用 THsuanluComponent1::TestFunc 成員函數(shù)盈咳,沒(méi)有頭文件耿眉,不知道類的具體定義和實(shí)現(xiàn)。
由于動(dòng)態(tài)加載組件包不需要頭文件和鏈接庫(kù)文件鱼响,這個(gè)例子直接在按鈕點(diǎn)擊事件里面:通過(guò) Sysutils::LoadPackage 加載 bpl 包鸣剪,通過(guò)函數(shù)名創(chuàng)建對(duì)象,通過(guò)成員函數(shù)名調(diào)用成員函數(shù)丈积,然后通過(guò) Sysutils::FreeAndNil 釋放對(duì)象占用資源筐骇,然后通過(guò) Sysutils::UnloadPackage 釋放 bpl 包占用的資源。
TMethod 有兩個(gè)成員:Code 和 Data江滨,是 __closure 的組成铛纬,調(diào)用這個(gè) __closure 指針相當(dāng)于調(diào)用 Data->Code(); 其中 Data 直接指向?qū)ο螅珻ode 指向 MethodAddress 方法獲取的成員函數(shù)的地址唬滑。
void __fastcall TForm1::Button1Click(TObject *Sender)
{
try
{
NativeUInt hPackage = Sysutils::LoadPackage(L"HsuanluTestPackage.bpl");
TObject *__stdcall (*pfCreate)(void) = (TObject *__stdcall(*)(void))::GetProcAddress((HINSTANCE)hPackage, "CreateComponent1");
if(pfCreate)
{
TObject *pComponent = pfCreate();
TMethod Method;
Method.Code = pComponent->MethodAddress(L"TestFunc");
Method.Data = pComponent;
typedef void (__closure *pFunc)(void);
(*(pFunc*)&Method)();
Sysutils::FreeAndNil(&pComponent);
}
Sysutils::UnloadPackage(hPackage);
}
catch(Exception &e)
{
ShowMessage(e.Message);
}
}
運(yùn)行結(jié)果:
相關(guān):
- System::Sysutils::LoadPackage
- System::Sysutils::UnloadPackage
- System::Sysutils::InitializePackage
- System::Sysutils::FinalizePackage
- System::Sysutils::GetModuleName
- System::Sysutils::GetPackageInfo
- System::Sysutils::GetPackageDescription
- System::Sysutils::GetPackageTargets
- System::Sysutils
- C++ Builder 本地化 (多語(yǔ)言) 功能
- C++ Builder 的字符串類型告唆、字符類型、字符編碼
- C++ Builder 的反射 (三) - 通用 Reflection Factory
- C++ Builder 的反射 (二) - Reflection Factory
- C++ Builder 的反射 (一) - Reflection 簡(jiǎn)單實(shí)現(xiàn)
- 枚舉控件所有的屬性晶密、事件和方法
- 枚舉窗口內(nèi)所有的控件
- C++ Builder 的枚舉類型
- C / C++ 可變參數(shù)的函數(shù)
- C / C++ 可變參數(shù)的宏擒悬,__VA_ARGS__,...
- C++ 可變參數(shù)的模板
- C++ Builder 的 PME 架構(gòu)
C++ Builder 參考手冊(cè) ? 創(chuàng)建和使用動(dòng)態(tài)加載的包 (.bpl)