bpl插件系统开发(1)

半路出家的delphier一如我,对于win32api式的调用有着近乎厌恶的抵触情绪,我很早以前看c++的教程时看到lptrXXXXX的变量就头大,以至于到现在都不会用c++,都不曾写成功过那怕一个hello world程序,所以对于dll式的导出函数后面加stdcall使用右到左的参数调用方式,总觉得没有delphi的美感.再加上看到了许多bpl可以导出类,而dll很麻烦的文章,更是坚定了我的方向.

   开始吧.....

 

   一个插件系统需要什么?

      一个最小的插件系统当然需要插件本身,调用插件的容器,最后需要契约.

      契约是什么呢?契约就是两个对象相互沟通的一个标准,这个标准应该统一,这样容器才能和不同的插件通讯.我们可以使用接口来表述这个契约.例如

type
    IPlugin = interface
        ['{48BF4000-B028-4B57-9955-B1A8305DA394}']
        procedure Execute;
    end;

      容器,它可以配置加载哪些插件,并能调用插件的功能,并和插件交互数据,这种数据应该有统一性,因此我们的目标当然是需要和插件能够交互TObject,因为我们可以封装任何的数据在TObject中去,至于这个TObject中是些什么什么数据,只需要插件和容器知道就可以了.那么我们修改契约如下:

type
    IPlugin = interface
        ['{48BF4000-B028-4B57-9955-B1A8305DA394}']
        function GetObject: TObject;
        procedure SetObject( value: TObject );
        procedure Execute;
    end;

      插件,我们使用实现了接口的一个bpl来构建插件,让容器动态载入一个bpl,然后访问其中的IPlugin来调用插件

coding吧

我们构造一个容器,它动态的载入一个bpl,并且通过预定义的名称来访问其中的 IPlugin,并调用IPlugin.Execute,这个预定义的名称其实是在bpl中实现了IPlugin的类的名称,这个类的名称我们可以通过修改bpl的名称或者同时发布一个配置文件来让容器获得.现在我们先暂时写死在程序里,毕竟这个问题是个小问题

 

构建插件

   new->package生成一个package,就用'package1'的缺省名称,new->unit

unit TPluginImpl1;

interface

uses uIPlugin, dialogs, Classes;

type
{$M+}
    TPlugin = class( TInterfacedPersistent, IPlugin )
        function GetObject: TObject;
        procedure SetObject( value: TObject );
        procedure Execute;
    private
        FMsg: string;
    public
        procedure AfterConstruction; override;
    end;
{$M-}
implementation

{ TPlugin }

procedure TPlugin.AfterConstruction;
begin
    inherited;
    FMsg := 'init String';
end;

procedure TPlugin.Execute;
begin
    showmessage( FMsg );
end;

function TPlugin.GetObject: TObject;
begin
    result := TObject( FMsg );
end;

procedure TPlugin.SetObject( value: TObject );
begin
    FMsg := string( Value );
end;

initialization
    RegisterClass( TPlugin );

finalization
    UnRegisterClass( TPlugin );

end.

TPlugin实现了IPlugin接口,并且注册了该组件,使它能够被容器访问到.

compile,之后,会在%delphi%/bpl目录生成package1.bpl.

构建容器

procedure TForm3.Button1Click( Sender: TObject );
var
    theClass             : TPersistentClass;
    thePlugin            : TPersistent;
    IPlug                : IPlugin;
    FPackege             : Cardinal;
begin
    FPackege := LoadPackage( 'package1.bpl' ); //加载包

    theClass := GetClass( 'TPlugin' );  //通过字符串获得类定义
    if theClass = nil then
    begin
        ShowMessage( 'TPlugin not load' );
        exit;
    end;
    thePlugin := theClass.Create;       //创建实例
    Supports( thePlugin, StringToGUID( '{48BF4000-B028-4B57-9955-B1A8305DA394}'
        ), IPlug );                     //转换成IPlugin接口
    try
        IPlug.Execute;                  //执行插件的
    finally
        IPlug := nil;
    end;
    UnloadPackage( FPackege );          //卸载包
end;

project->options->package

点选build with  runtime package

修改成vcl;rtl,确定

可以发布测试了

拷贝你的project1.exe,package1,windowSystem32目录下的vcl70.bpl,rtl70.bpl到一个目录,把他们拷贝到一个目录下,发布到一个没有delphi的机器上试试吧.

你可能感兴趣的:(bpl插件系统开发(1))