delphi的BPL应用

最近一直在测试BPL和DLL,总结一下这段时间的经验。
如果是模块化架构,就选择BPL,不要选择DLL,DLL可以对外做接口使用,不过Delphi接口我觉得DataSnap更方便点。为什么要用BPL呢,因为DLL是无法传递对象的,只能传递对象的内存地址过去。BPL就可以实现对象的传递。
使用BPL的注意事项,首先一定要注意Debug 和Release 两种编译是有很大区别的。直接Release编译最好,主程序也要用Release编译调用,如果编译类型不同,会有异常提示。BPL里面各个Form和Unit之间的调用,需要注意的如果用到了Form的控件,记得一定要把Form对象传过去。这样获取才不会出问题。BPL调用BPL的时候,也要把Form传过去,传回来的时候再转换回来。下面说下调用案例。
我是一个主程序,两个BPL
主程序调用的代码

procedure TFMenuItem.Label1DblClick(Sender: TObject);
var
  BPLHandle: HMODULE;
  frm: TCustomForm;
  AClass : TPersistentClass;
  SetUser:procedure(sform:TForm;User:String;IP:String;Port:Integer);
  newPage:TAdvTabSheet;
  Path:String;
  ClassName:String;
  SetName:String;
begin
  //BPL的目录和名称
  Path:='System/'+Copy(self.Caption,1,2)+'.bpl';
  //调用的Form的名称
  ClassName:='T'+self.Caption;
  //BPL里面的过程名称
  SetName:=self.Caption+'SetUser';
  //加载BPL
  BPLHandle := LoadPackage(Path);
  //加载后获取过程
  @SetUser := GetProcAddress(BPLHandle, Pchar(SetName));
  if BPLHandle > 0 then
  begin
    //获取Form
    AClass := FindClass(ClassName);
    if AClass<>nil then
    begin
      //新增一个Page页面
      newPage:=TAdvTabSheet.Create(FMyMain.AdvPageControl2);
      newPage.Caption:=Label1.Caption;
      newPage.Color:=clWhite;
      newPage.AdvPageControl:=FMyMain.AdvPageControl2;
      newPage.ShowClose:=True;
      FMyMain.AdvPageControl2.ActivePage:=newPage;
      //创建BPL的Form实例
      frm:=TComponentClass(AClass).Create(Application) as TCustomForm;
      if @SetUser<>nil then
        //执行BPL里面的过程
        SetUser(TForm(frm),'admin',FMyMain.DSRestConnection1.Host,FMyMain.DSRestConnection1.Port);
      //放入新建的Page里面
      frm.Parent:=newPage;
      //显示
      frm.Show;
     // frm.Free;
    end
  end
end;

第一个BPL的代码

unit User;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, DBGridEhGrouping, ToolCtrlsEh,
  DBGridEhToolCtrls, DynVarsEh, FireDAC.Stan.Intf, FireDAC.Stan.Option,
  FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf,
  FireDAC.DApt.Intf, Vcl.ComCtrls, Vcl.ToolWin, System.ImageList, Vcl.ImgList,
  Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, EhLibVCL, GridsEh,
  DBAxisGridsEh, DBGridEh, AdvEdit, AdvEdBtn, Vcl.StdCtrls, Vcl.ExtCtrls,
  Datasnap.DSClientRest, FireDAC.Stan.StorageJSON,
  FireDAC.Stan.StorageXML, FireDAC.Stan.StorageBin,DataBase;

type
  //定义回调过程
  MeADD=procedure(DepCode:String;DepName:String;MyForm:TForm);
  TF901 = class(TForm)
    Panel1: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    Edit7: TEdit;
    Edit6: TAdvEditBtn;
    Panel2: TPanel;
    DBGridEh1: TDBGridEh;
    Panel3: TPanel;
    DataSource1: TDataSource;
    FDMemTable1: TFDMemTable;
    ImageList1: TImageList;
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    ToolButton4: TToolButton;
    ToolButton10: TToolButton;
    ToolButton5: TToolButton;
    ToolButton6: TToolButton;
    ToolButton7: TToolButton;
    ToolButton8: TToolButton;
    procedure ToolButton1Click(Sender: TObject);
    procedure ToolButton2Click(Sender: TObject);
    procedure ToolButton3Click(Sender: TObject);
    procedure ToolButton4Click(Sender: TObject);
    procedure ToolButton10Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ToolButton8Click(Sender: TObject);
    procedure Edit6ClickBtn(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    var
      UserNo:String;
      MyDataBase:TDDataBase;
  end;
  //定义给主程序调用的过程
  procedure F901SetUser(sform:TForm;UserNo:String;IP:String;Port:Integer);
  //定义一个跟回调过程一样的过程,这个用于回调过程功能实现
  procedure SetDep(depcode:String;depname:String;MyForm:TForm);
var
  F901: TF901;

implementation
Uses DataPost;
{$R *.dfm}

//给主程序调用的过程
procedure F901SetUser(sform:TForm;UserNo:String;IP:String;Port:Integer);
begin
   TF901(sform).UserNo:=UserNo;
   TF901(sform).MyDataBase:=DataPost.ConnectData(IP,Port);
end;

//一个跟回调过程一样的过程,这个用于回调过程功能实现
procedure SetDep(depcode:String;depname:String;MyForm:TForm);
begin
   TF901(MyForm).Edit7.Text:=depcode;
   TF901(MyForm).Edit6.Text:=depname;
end;

//BPL里面调用另外一个BPL
procedure TF901.Edit6ClickBtn(Sender: TObject);
var
  BPLHandle: HMODULE;
  frm: TCustomForm;
  AClass : TPersistentClass;
  DepSetUser:procedure(sform:TForm;tForm:TForm;User:String;IP:String;Port:Integer);
  PMeADD:procedure(me:MeADD);
begin
  //加载BPL
  BPLHandle := LoadPackage('Share/DepBPL.bpl');
  //这里跟主程序调用的一样,调用另外一个BPL的过程
  @DepSetUser := GetProcAddress(BPLHandle, 'DepSetUser');
  //另外一个BPL回调本BPL的过程
  @PMeADD := GetProcAddress(BPLHandle, 'PMeADD');
  if BPLHandle > 0 then
  begin
    //获取Form
    AClass := FindClass('TFQueryDep');
    if AClass<>nil then
    begin
      //创建另外一个BPL的Form实例
      frm:=TComponentClass(AClass).Create(Application) as TCustomForm;
      if @DepSetUser<>nil then
      //调用里面的过程 
       DepSetUser(TForm(frm),self,'admin',MyDataBase.DSRestConnection1.Host,MyDataBase.DSRestConnection1.Port);
      if @PMeADD<>nil then
       //把实现回调功能的过程传过去
        PMeADD(SetDep);
      frm.ShowModal;
      frm.Free;
    end
  end

end;

procedure TF901.FormShow(Sender: TObject);
begin
  DataPost.ButtonPower(Self.Name,self.UserNo,self.ToolBar1,self.MyDataBase);
  DataPost.F901OpenData(self);
end;

procedure TF901.ToolButton10Click(Sender: TObject);
begin
  DataPost.F901Cancel(self);
end;

procedure TF901.ToolButton1Click(Sender: TObject);
begin
   DataPost.F901Add(self);
end;

procedure TF901.ToolButton2Click(Sender: TObject);
begin
  DataPost.F901Update(self);
end;

procedure TF901.ToolButton3Click(Sender: TObject);
begin
  DataPost.F901Delete(self);

end;

procedure TF901.ToolButton4Click(Sender: TObject);
begin
  DataPost.F901Save(self);
end;

procedure TF901.ToolButton8Click(Sender: TObject);
begin
  DataPost.F901Cancel(self);
end;

//这里是给主程序显示可调用的过程
exports
    F901SetUser;
    
//这里把Form给主程序定位Form使用
initialization
  RegisterClass(TF901);
finalization
  UnRegisterClass(TF901);

end.

第二个BPL代码

unit QueryDep;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, DBGridEhGrouping, ToolCtrlsEh,
  DBGridEhToolCtrls, DynVarsEh, EhLibVCL, GridsEh, DBAxisGridsEh, DBGridEh,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
  FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
  FireDAC.Stan.Async, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet,
  FireDAC.Comp.Client, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Imaging.pngimage,Vcl.ShadowForms,
  Datasnap.DSClientRest,system.IniFiles,Data.FireDACJSONReflect,
  FireDAC.Stan.StorageXML, FireDAC.Stan.StorageJSON, FireDAC.Stan.StorageBin;

type
  //定义回调过程
  MeADD=procedure(DepCode:String;DepName:String;MyForm:TForm);
  TFQueryDep = class(TShadowForm)
    DBGridEh1: TDBGridEh;
    DataSource1: TDataSource;
    Panel1: TPanel;
    Label4: TLabel;
    Image1: TImage;
    Panel3: TPanel;
    Panel4: TPanel;
    DSRestConnection1: TDSRestConnection;
    FDMemTable1: TFDMemTable;
    FDStanStorageBinLink1: TFDStanStorageBinLink;
    FDStanStorageJSONLink1: TFDStanStorageJSONLink;
    FDStanStorageXMLLink1: TFDStanStorageXMLLink;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDestroy(Sender: TObject);
    procedure DBGridEh1DblClick(Sender: TObject);
    procedure Image1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    var
      UserNo:String;
      //用于接收上一个BPL的Form,后面调用回调过程的时候会传回去
      Form:TForm;
  end;
  //顶一个回调过程功能实现,用于调用上一个BPL的回调过程接收
  procedure PMeADD(me:MeADD);
  //定义上一个BPL调用过程
  procedure DepSetUser(sform:TForm;UserNo:String;IP:String;Port:Integer);


var
  FQueryDep: TFQueryDep;
  FMeADD:MeADD;

implementation
Uses Server;

{$R *.dfm}
//上一个BPL调用过程的功能实现
procedure DepSetUser(sform:TForm;UserNo:String;IP:String;Port:Integer);
begin
   TFQueryDep(sform).UserNo:=UserNo;
   TFQueryDep(sform).Form:=sform;
   TFQueryDep(sform).DSRestConnection1.Host:=IP;
   TFQueryDep(sform).DSRestConnection1.Port:=Port;
end;
//用于接收传过来的过程
procedure PMeADD(me:MeADD);
begin
  FMeADD:=ME;
end;

procedure TFQueryDep.DBGridEh1DblClick(Sender: TObject);
begin
//调用回调过程,把值和Form传回去   FMeADD(DBGridEh1.DataSource.DataSet.FieldByName('cDepCode').AsString,DBGridEh1.DataSource.DataSet.FieldByName('cDepName').AsString,Form);
   close;
end;

procedure TFQueryDep.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  //  Action := caFree;
end;

procedure TFQueryDep.FormDestroy(Sender: TObject);
begin
   FQueryDep := nil;
end;

procedure TFQueryDep.FormShow(Sender: TObject);
var
  Server: TServerMethods1Client;
  DSlIST: TFDJSONDataSets;
begin
  Server := TServerMethods1Client.Create(DSRestConnection1);
  DSlIST := Server.ServerGetTable('select * from Department order by cDepCode', UserNo, 1);
  FDMemTable1.FieldDefs.Clear;
  FDMemTable1.Close;
  FDMemTable1.Data := TFDJSONDataSetsReader.GetListValue(DSlIST, 0).Data;
  FDMemTable1.Open;
end;

procedure TFQueryDep.Image1Click(Sender: TObject);
begin
  close;
end;

//给另外一个BPL获取过程使用
exports
    PMeADD,DepSetUser;

//给另外一个BPL获取Form使用
initialization
  RegisterClass(TFQueryDep);
finalization
  UnRegisterClass(TFQueryDep);

end.

主要代码就这些
调用第一个BPL
在这里插入图片描述
通过第一个BPL调用第二个BPL

在这里插入图片描述

点击后,把第二个BPL的值,通过回调过程传递到一个BPL里面
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于程序员来说,要凭一己之力开发出漂亮逼真的工控仪表和工控图表是非常耗时间和精力的,那么使用专业的第三方控件就是不错的选择,不仅节约开发时间,降低了项目风险,最重要的是第三方控件写的程序更专业,工控图表图像更精细。笔者认为最好用的工控控件当属 Iocomp 和 ProEssentials。下面笔者对这两个工控控件进行了简单的对比评测: Iocomp工控仪表 Iocomp公司可以说是工业仪表盘控件的龙头老大,在国内工业自动化集成商中,尤其是OPC项目,采用Iocomp产品进行仪表设计的项目越来越多。Iocomp旗下一共有Iocomp .Net WinForms、Iocomp .Net Compact Framework、Iocomp ActiveX/VCL三个产品,用得最多的是最后一个。每个产品分标准版(standard)、专业版(Pro)、绘图版(Plot)、终极版(Ultimate)四个版本,开发者可以根据自己的需要进行选择。下面重点跟大家介绍下Iocomp ActiveX/VCL。 优点: 丰富的VB例程使用户能够快速的掌握各种控件的使用方法。 运行于Windows7/NT4.0 等32位Windows平台,目前尚未支持Windows 8。有效的利用了32位Windows平台的多任务能力,可达到工控软件的实时要求。 全部控件均由Delphi编写,代码短小精悍,执行快速、占用系统资源少。完美的Windows图形函数调用使得各控件在动画时绝无一般软件屏幕刷新时产生的闪烁现象。 有效的补充了Visual Basic等开发工具应用于工控环境的不足,使Visual类软件更好的应用于工业控制中。 可应用于科学、工程、医疗、石油、天然气、半导体、工厂自动化、航空航天、军事、电信、建筑等领域。所有的Iocomp控件都是基于OPC的,使用它开发工业类软件可以事半功倍。 与Windows原有控件的兼容良好,使用户的软件开发难度降到最低。用户可以方便的利用各种Visual类软件在数据库处理、报表打印以及系统调用和网络上的优势等开发出功能强大的工业控制软件。 它不同于各种其它工控组态软件,无须学习专用语言和复杂的函数调用。用户只要会自己擅长的Basic、Pascal等即可在Visual Basic、Delphi等开发环境下快速的开发出各种工业控制软件。 界面效果丰富。几十余种控件(包括各种形式的仪表、调节旋钮、指示灯、LED数码管等)可以根据具体应用自定义各种属性而演变为几十种界面表达方式。 bpl格式,一键安装!
delphi / c++ builder 10.1 Berlin 安装Intraweb 14.1.5,仅供学习研究使用 说明:仅供学习研究使用 安装程序太大无法上传,请先到http://www.atozed.com下载iw14.1.5.exe 本人用的是Embarcadero RAD Studio 10.1 Berlin up2 1. 打开IDE,Component / Install Packages...,选择旧版本Intrawebxxxx.bpl,Remove. 2.用IWBundledRemovalTool工具将旧版本文件删除(如果没有此工具可从网上下载或先随便安装一个版本,把此工具复制出来)。 3.如果需要用bcb开发由进行这一步,如只需要用delphi开发则可跳过这步, 将C:\Program Files (x86)\Embarcadero\Studio\18.0\include\windows\vcl目录下IW*.hpp删除。 4.如果需要用bcb开发由进行这一步,如只需要用delphi开发则可跳过这步,本人前几次安装都没有成功, 后面增加了这步,不知道此步是否必须, 将C:\Program Files (x86)\Embarcadero\Studio\18.0\include\windows\vcl目录下, 从InAntiFreezeBase.hpp开始选中到InYarn.hpp,然后将这些文件删除。 5.运行iw14.1.5.exe安装,安装时输入如下LicenseKey(这个号也是网上找到的,由于找了一天也不记得在哪找到的了,感谢作者提供): +0010AAIACIABCAACABCACGABCABAAAGACGABCAAGABEAAEABEABIABEAAGABEAAIABCAACABCACEABEABGABEAAAAAAACGAAAACAAAIAAGABCADAABCACGABEAAAABCAACABCACIABEABIAAGACGAAIAACABEAAIABCADAABEACAABCABAABCAAIAAEAAAABAAAGABCADAABCABCABEAAIABEABEABCAACABEAAEABCABAAAAACGAAAACAAAIAAIABCABAABEABCABCABAABCACEABCADAABEAAAABCABAABEAAEAAGACGABCAAGABEAAEABEABIABEAAGABEAAIABCAACABCACEABEABGABEAAAAAAACGAAAACAAAIABAABEABGABEAAAABCABIABEAAEABCAACABEAAIABCABIABCADAABCACIAAGACGAAGABAAAGABGAAGABCAAGAAAAAGABGAAAACGAAAACAAAIABAABCAAIABCABIABEAAIABCABIABCADAABCACIAAGACGAAIABAAAIACIABAAAIAAAACGAAAACAABAAAGABCABAABEAAEABCABIABCAACABCACEAAIACIABCADAAAGACGAAGAAEAAGAAAAAGAACAAGABCAAGABAAAGAAAAAGABCAAGABGAAGABGAAAACGAAAACAAAIABAABCACGABCAACABCABIABCACEAAGACGAAAACGAAAACAAAIABGABCAACABEAAGABCABGAAGACGAAAACGAAAACAAAHAEDAAFACI 6.安装完成后如果选中License Registration则同样输入上面的LicenseKey。 7.先启动Delphi 10.1 Berlin IDE,Tools/Options,将iw14.1.5.exe安装目录(本人安装到C:\Program Files (x86)\IntraWeb XIV)下的LibD10_1W32、LibD10_1W64、Source三个目录添加到Library Path和Browsing Path。 8.随便创建一个Intraweb应用,选择win32平台,然后运行,报错后修改IWLicenseKey.pas: 将SetLicenseKey(xxxxxxxxxxxxxxxxxx改为: SetLicenseKey( '+0010AAIACIABCAACABCACGABCABAAAGACGABCAAGABEAAEAB'+ 'EABIABEAAGABEAAIABCAACABCACEABEABGABEAAAAAAACGAAA'+ 'ACAAAIAAGABCADAABCACGABEAAAABCAACABCACIABEABIAAGA'+

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值