您的位置:首页 > 编程语言 > Delphi

让你的程序支持插件

2004-08-21 23:02 435 查看
源码 http://www.aidelphi.com/6to23/docu/plugin.zip      
相信各位应该都用过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过程。<
131f5
/span>
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。
 <?XML:NAMESPACE PREFIX = O />

完成后运行,发现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的实现不同之外,其余均是相同的。在此不重复。相信读者也能自行完成。笔者的主页http://www.aidelphi.com上有该例程最完整的代码。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐