zoukankan      html  css  js  c++  java
  • 让程序支持插件

    相信各位应该都用过WinAmp,也相信它对插件的支持是它最终流行起来的主要原因。能不能让我们自已的程序也支持插件呢,以面我们就用Delphi来为我们编第一个支持插件的程序。

    对于一般用户来说,插件就是一个DLL文件,但与一般DLL不同的是,插件支持对主程序功能的扩展,主程序没有插件也一样能运行,但一般的DLL大多数是主程序不可缺少的部份。当需要经常为客户更新应用程序版本时,插件也许是你不错有选择。

    首先,在编写应用程序之前需要清楚应用程序本身可以完成什么主要功能,需要扩展什么样的功能,因为插件本身是通过主程序提供的特定接口来与主程序进行行交互的,在编写主程序时你需要确定这些接口。在本例中,定义了两个接口,一个完成插件的初始化,主要是指选择并载入相应的图片,另一个是在主Form重绘时绘制出相应的图片,其中第二个接口需要传递画布句柄和绘制区域。

    以下是主程序主Form interface段的定义:

    TPluginDescribe = Function:Boolean; stdcall;

    TPluginDrawDescribe = procedure(DC:HDC;Rect:TRect); stdcall;

    TForm1 = class(TForm)

    ListBox1: TListBox;

    procedure FormCreate(Sender: TObject);

    procedure ListBox1DblClick(Sender: TObject);

    procedure FormPaint(Sender: TObject);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    private

    LibHandle: HMODULE;

    DwarProc: TPluginDrawDescribe;

    procedure LoadPlugins;

    procedure LoadPlugin(sr: TSearchRec);

    { Private declarations }

    public

    { Public declarations }

    end;

    其中定义了一个过程类型和一个函数类型,其中过程类型有两个变量,一个HDC类型的画布句柄,另一个是TRECT类型的绘制区域。TForm1有两个私有字段LibHandle和DwarProc用于保存装入的插件DLL的句柄和绘图过程句柄。

    在主Form创建时检查是否有插件程序,就列出可用插件,TForm1的OnCreate事件句柄FormCreate实现代码如下:

    procedure TForm1.FormCreate(Sender: TObject);

    begin

    LibHandle:=0;//初始化LibHandle的值。

    LoadPlugins;//调入LoadPlugins过程。

    end;

    以下是LoadPlugins的实现代码:

    procedure TForm1.LoadPlugins;

    var

    sr: TSearchRec;

    path: string;

    Found: Integer;

    begin

    path := ExtractFilePath(Application.Exename);

    try

    Found := FindFirst(path + ‘*.DLL‘, 0, sr);

    while Found = 0 do//查找文件。

    begin

    LoadPlugin(sr);

    Found := FindNext(sr);

    end;

    finally

    FindClose(sr);

    end;

    end;

    查找当前路径下所有扩展名为DLL的文件,如果找到则检查是否为本例插件。

    检查插件文件的过程LoadPlugin实现代码如下:

    procedure TForm1.LoadPlugin(sr: TSearchRec);

    var

    iLibHandle: HMODULE;

    pDescribeProc: TPluginDescribe;

    pDwarProc: TPluginDrawDescribe;

    begin

    iLibHandle := LoadLibrary(Pchar(sr.Name));

    if iLibHandle <> 0 then

    begin

    try

    pDescribeProc := GetProcAddress(iLibHandle, ‘loadpicture‘);

    pDwarProc := GetProcAddress(iLibHandle, ‘drawpicture‘);

    if Assigned(pDescribeProc) and Assigned(pDwarProc) then

    ListBox1.Items.Add(sr.Name);

    finally

    FreeLibrary(iLibHandle);

    end;

    end else

    ShowMessage(‘loading Dll file error!‘);

    end;

    首先动态装入插件库使用LoadLibrary API函数,如果其中有接口过程,则将文件名加入到ListBox1中。其中GetProcAddress是获得DLL中某个例程的地址。不使用DLL时用FreeLibrary卸载。

    在ListBox1的双击事件中才真正启动插件:

    procedure TForm1.ListBox1DblClick(Sender: TObject);

    var pDescribeProc: TPluginDescribe;

    begin

    if ListBox1.ItemIndex<>-1 then

    begin

    if LibHandle<>0 then

    FreeLibrary(LibHandle);

    DwarProc:=nil;

    LibHandle := LoadLibrary(PChar(ListBox1.Items[ListBox1.ItemIndex]));

    if LibHandle <> 0 then

    begin

    try

    pDescribeProc := GetProcAddress(LibHandle, ‘loadpicture‘);

    if pDescribeProc then

    begin

    DwarProc := GetProcAddress(LibHandle, ‘drawpicture‘);

    Invalidate;

    end;

    Except

    FreeLibrary(LibHandle);

    LibHandle:=0;

    end;

    end

    else

    ShowMessage(‘loading Dll file error!‘);

    end;

    end;

    //这段代码主要是先调用装入图片的插件过程,如果成功,则取绘图片的过程地址。只有LibHandle<>0和给DwarProc赋值之后才算真正启动了插件。

    在TForm1的OnPaint事件中调用DwarProc过程,启动插件中的绘图过程:

    procedure TForm1.FormPaint(Sender: TObject);

    begin

    try

    if (LibHandle<>0) and Assigned(DwarProc) then

    DwarProc(Self.Canvas.Handle,Self.ClientRect);

    Except

    if LibHandle<>0 then

    begin

    FreeLibrary(LibHandle);

    LibHandle:=0;

    end;

    end;

    end;

    最后别忘了在TForm1的OnClose事件中卸载DLL。



    完成后运行,发现ListBox1中什么也没有,因为插件程序还没有建立。

    本例共有两个插件,一个完成图片在主Form上的平铺绘制,另一个完成缩放绘制。

    插件程序主单元如下:

    library PlugIn1;



    uses

    SysUtils,

    Classes,

    PlugInUnit1 in ‘PlugInUnit1.pas‘;



    exports loadpicture,drawpicture;

    //导出两个过程。

    begin

    end.

    两个过程的定义和实现代码在单元PlugInUnit1中:

    unit PlugInUnit1;



    interface

    Uses Graphics,extdlgs,Windows;



    Function loadpicture:Boolean;

    procedure drawpicture(DC:HDC;Rect:TRect);export; stdcall;



    Var Picture:TPicture;



    implementation



    procedure drawpicture(DC:HDC;Rect:TRect);

    Var cCanvas:TCanvas;

    begin

    if (Picture<>nil) and not Picture.Graphic.Empty then

    begin

    cCanvas:=TCanvas.Create;

    try

    cCanvas.Handle:=DC;

    cCanvas.StretchDraw(Rect,Picture.Graphic);

    finally

    cCanvas.Free;

    end;

    end;

    end;



    Function loadpicture:Boolean;

    begin

    Result:=False;

    Picture:=TPicture.Create;

    with TopenpictureDialog.Create(nil) do

    begin

    try

    if Execute then

    begin

    Picture.LoadFromFile(FileName);

    Result:=True;

    end;

    finally

    Free;

    end;

    end;
    end;

    end.

    上面的插件完成图片的缩放绘制,另一个插件的代码除单元名和drawpicture的实现不同之外,其余均是相同的。在此不重复。相信读者也能自行完成。

  • 相关阅读:
    Python_soket
    Python_正则表达式语法
    Python_math模块
    Python_random模块
    Python_os模块
    Python_time模块
    Java技能树-图片版
    读书笔记---《编写可读代码的艺术》
    Java代码优化建议
    Git常用命令
  • 原文地址:https://www.cnblogs.com/martian6125/p/9631551.html
Copyright © 2011-2022 走看看