Bpl的使用以及与Dll的区别
Bpl就是Dll,这句话当然没错。
简单的例子,当然可以做,而且可以做得很好,我就曾把左兄的离线浏览器改成了这样一
个版本: 实现多个数据连接方式,ADO、DOA、ODAC、IBX、KAO,每个连接对应它的特定数据
库,都以一个独立的BPL来实现;主程序没有任何连接数据库的代码,主窗体切换版本时只要
这样一段代码就行了:
class function TfrmMain.SelectVersion(AReadSettings: Boolean): Boolean;
var
DMPkg, DMClassName: string;
I: Integer;
UserCanceled: Boolean;
begin
Result := False;
repeat
DMPkg := 'DoaDmDLL.bpl';
//简单版本,直接提示用户输入bpl的名称
UserCanceled := not InputQuery(Application.Title, 'ModuleName:', DMPkg);
DMClassName := GetPackageDescription(PChar(DMPkg));
I := Pos('[RICHEXPRDM]', DMClassName);
try
DM := nil;
except
end;
//是正确的BPL,则开始载入
if I > 0 then
begin
//取得Datamodule的类名
DMClassName := Trim(Copy(DMClassName, I + 12, MAX_PATH));
//卸载当前的BPL
UnloadCurPkg;
//用LoadPackage载入刚刚选择的BPL
FHandle := LoadPackage(DMPkg);
//创建Datamodule的实例
DM := TDMClass(FindClass(DMClassName)).Create(Application);
Result := True;
end
else
Application.MessageBox('非法的DLL', '', MB_OK or MB_ICONERROR);
until Result or UserCanceled;
end;
然后在DoaDM.pas里加这两句:
initialization
RegisterClass(TDoaDM);
finalization
UnregisterClass(TDoaDM);
编译成一个BPL就OK了。
这样用BPL做起来真的是非常简便,只要用LoadPackage以后,各单元就跟你直接uses差不多
了,initialization及finalization也会帮你执行,然后你就当做不存在BPL这回事一样用
就OK了。 这是BPL的好处,可以很方便的划分现有的代码成相对独立的模块。
但是,它也有几个致命的缺点,首先它无法象DLL一样,把它引用到的某一个或某几个BPL里的内
容编译进去,也就是说,只要你这个BPL引用了另一个BPL,发布的时候就必须两个BPL一起发
布,另外,只要一个BPL引用了某一个单元,其他的BPL就不能直接引用那个单元编译,而必须
引用一个公用的包含此单元的BPL,否则你这两个BPL是无法同时Load的。有了这两点,对于
大型项目来说,做起来是非常复杂的,各个模块之间的关系很难处理好,不象DLL,编译出
来后,各成各的体系,不会说因为这个DLL引用了这个单元,另一个DLL必须通过其他引用了
此单元的DLL来引用那个单元。
Delphi中Package是一件非常强大的工具,用的好可以起到非常清晰的
划分程序结构的作用。因为他内建描述信息,可以和当前代码无缝集成起来,
可以保护包括类在内的任何元素,相当于VC中的MFC Extension DLL的作用。
但是一直以来的文章都只介绍静态连接的方法,这其实限制了Package的使用
因为静态连接的Package失去了其灵活性,可配置性等等。至于通过函数入口
方式访问,实在是大材小用,那不如直接用DLL还方便一些。
如何动态载入Package,使用其中的类、函数、变量等等?起始说穿了很
简单,就是做一个代理包。因为在一个Delphi程序中,每个unit只能存在
一份,否则发生冲突。要动态载入包,又得取得其中信息,又不能直接uses
包含信息的unit(否则引起冲突),解决办法是另外建一个代理包来作为桥梁
传递信息。下面是一个简单的例子,主程序使用到两个包,DemoPak包中有
一个简单的Form;RegPak是所谓的代理包,起到注册信息的作用。
主程序对RegPak静态使用(在Project Options里面设置了),对DemoPak
动态载入(通过LoadPackage),而DemoPak依赖于RegPak(requires),
并在初始化时向代理包RegPak注册自己的可用类,这里举例注册类信息,
你可以方便的改成注册其他信息
unit FormReg;
interface
uses
Classes, SysUtils, Forms, Contnrs;
type
TFormClass = class of TForm;
procedure RegisterFormClass(const AName: string; const AFormClass: TFormClass);
procedure UnregisterFormClass(const AName: string);
function FindFormClass(const AName: string): TFormClass;
implementation
var
g_lstNames: TStringList;
g_lstForms: TClassList;
procedure RegisterFormClass(const AName: string; const AFormClass: TFormClass);
begin
g_lstNames.Add(AName);
g_lstForms.Add(AFormClass);
end;
procedure UnregisterFormClass(const AName: string);
var
Index: Integer;
begin
Index := g_lstNames.IndexOf(AName);
if Index <> -1 then
begin
g_lstNames.Delete(Index);
g_lstForms.Delete(Index);
end;
end;
function FindFormClass(const AName: string): TFormClass;
var
I: Integer;
begin
for I := 0 to g_lstNames.Count - 1 do
begin
if g_lstNames[I] = AName then
begin
Result := TFormClass(g_lstForms.Items[I]);
Exit;
end;
end;
Result := nil;
end;
initialization
g_lstNames := TStringList.Create;
g_lstForms := TClassList.Create;
finalization
FreeAndNil(g_lstForms);
FreeAndNil(g_lstNames);
end.
以上是RegPak的主要代码,因为举例,代码很简陋。主要思想就是保存注册信息,
提供查询方法。让我们看看在DemoPak中的使用
unit AboutForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TfrmAbout = class(TForm)
lblAbout: TLabel;
private
public
end;
var
frmAbout: TfrmAbout;
implementation
uses FormReg;
{$R *.dfm}
initialization
RegisterFormClass(TfrmAbout.ClassName, TfrmAbout);
finalization
UnregisterFormClass(TfrmAbout.ClassName);
end.
在初始化时向RegPak的FormReg单元提交自己的类信息,因为每个Package在载入时
无论动态静态都会自动初始化,而RegPak被主程序静态引用,肯定已经初始化,所以直接
注册即可,非常简单。最后看看主程序中的使用
uses
FormReg;
procedure TfrmMain.btnAboutClick(Sender: TObject);
var
hModule: THandle;
begin
hModule := LoadPackage('DemoPak.bpl');
try
with FindFormClass('TfrmAbout').Create(nil) do
try
ShowModal;
finally
Free;
end;
finally
UnloadPackage(hModule);
end;
end;
动态载入需要的包,查询需要的类的信息,使用之,最后卸载包。
象dll样输出 我已试成功了,而且是在mdi中试成功的。
贴出代码,大家同喜。希望bbkxjy来拿分。
主要的原因是bpl输出的目录默认为/bpl下。
而我一直没有在意。
bpl部分;
...
type
TUIPackageForm = class(TForm)
DataSource1: TDataSource;
DBNavigator1: TDBNavigator;
DBGrid1: TDBGrid;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure ShowMDIChildForm(MainApp:TApplication);stdcall;
exports
ShowMDIChildForm;
var
UIPackageForm: TUIPackageForm;
implementation
{$R *.DFM}
procedure ShowMDIChildForm(MainApp:TApplication);stdcall;
begin
Application:=MainApp;
UIPackageForm:=TUIPackageForm.Create(MainApp);
UIPackageForm.Show;
end;
procedure TUIPackageForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action := cafree;
end;
动态调用的主程序部分。
type
Tshowmdiform=procedure(MainApp:TApplication);stdcall;
showmdiform:Tshowmdiform;
begin
UIConnect := LoadPackage('bpl');
showmdiform:=getprocaddress(UIConnect,'ShowMDIChildForm');
if (@showmdiform<>nil) then
showmdiform(application)
else showmessage('no prc');
end;
Bpl的使用以及与Dll的区别相关推荐
- Activex、OLE、COM、OCX、DLL之间区别、联系
转自:http://baike.baidu.com/view/393671.htm 概述 .ocx是ocx控件的扩展名,与.exe .dll同属于PE文件.下面说说什么是ocx控件! OCX 是对象类 ...
- OCX和DLL的区别
转自:http://blog.csdn.net/scucj/archive/2006/06/29/852181.aspx 一.关于DLL的介绍 DLL,动态链接库,Dynamic Lin ...
- C/C++ 知识点---LIB和DLL的区别与使用(网摘)
LIB和DLL的区别与使用 原文出处:[远风工作室] 共有两种库: 一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dyn ...
- LIB和DLL的区别与使用,非常详细
2019独角兽企业重金招聘Python工程师标准>>> 共有两种库: 一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供, ...
- [转]LIB和DLL的区别与使用
原文地址: http://www.cppblog.com/amazon/archive/2011/01/01/95318.html 共有两种库: 一种是LIB包含了函数所在的DLL文件和文件中函数位置 ...
- lib和dll的区别
lib和dll的区别 共有两种库: 一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link librar ...
- vs cpp生成h文件_lib 和 dll 的区别、生成以及使用详解
(给CPP开发者加星标,提升C/C++技能) 来源:tenoshttps://www.cnblogs.com/TenosDoIt/p/3203137.html [导读]:在日常开发中,我们只需要知道l ...
- LIB和DLL的区别与使用
LIB和DLL的区别与使用 转载于:https://www.cnblogs.com/jingzhishen/p/7088698.html
- VS中的lib和dll的区别和使用
LIB和DLL文件在创建工程项目时是必须要面对的,下面的文章讲述了如何添加LIB和DLL文件以及两者的区别. 1.加载lib/头文件 分两种方法: (1)适用于当前项目 1 第一步:项目->属性 ...
最新文章
- ueditor1.4.3配置过程(包含单独上传文件以及图片的使用)
- linux fall delay 10,Cell的Rise delay和Fall delay、Rise transition和fall transition
- 花了一晚上时间,终于把Python的基本用法归纳好了!
- 14、utf8和UTF-8在使用中的区别
- 2018热度上升最快的编程工具是什么?TensorFlow只排第11
- mac新手入门:在Mac上怎么使用夜览
- 基于 React.js + redux + bootstrap 的 RubyChina 示例
- [源码解读]position_estimator_inav_main解读(如何启动光流)
- 收藏、退出一气呵成,2019年机器之心干货教程都在这里了
- vivos9e防抖功能设置教程
- 百度地图,定位,添加图标
- 职场不接受Gap Year
- CSS学习笔记 01、CSS3基础知识学习
- java公路车的气嘴_自行车气嘴的分类、特性和打气的方法
- 【实战篇】37 # 如何使用 QCharts 图表库绘制常用数据图表?
- Linux系统安装过程详解
- 计算机系统的多级层次结构
- Nexus 05 第二种方式 使用Jenkins Nexus插件上传制品
- 【备份恢复】noarchive模式下使用增量备份恢复数据库
- python关键词 打标签详解_Python学习日记13|利用python制作简书首页热门文章关键词标签云...
热门文章
- MySQL----mysql_secure_installation 安全配置向导
- C# + PHP RSA保密通讯
- 全球10大B2B电子商务平台排行,这个网站只排第三!
- 2022最新Emlog新版导航源码 带用户中心
- Repeater的查询,添加,修改,删除
- Unity 中实现擦除功能
- Matlab:写入到 Diary 文件
- 知来路方知去处。坎坷已过,一马平川后必看的经典!——2018最新倾斜摄影建模与无人机航拍影像处理完美配置解决方案!
- 逻辑式编程语言极简实现(使用C#) - 1. 逻辑式编程语言介绍
- 佩戴骨传导耳机对耳朵有损害?不仅无损相比传统耳机优点有很多