如果是插件,那就是动态调入动态链接库的问题。。 1) LoadLibrary 函数L o a d L i b r a r y将D L L动态地装入内存。原型如下: H I N S TANCE LoadLibrary( LPCTSTR lpLibFileName // 指定模块所在的文件名 ) ; 2) GetProcAddress 函数G e t P r o c A d d r e s s获取D L L中指定模块的地址。原型如下: FARPROC GetProcAddress( HMODULE hModule, // DLL模块的句柄 LPCSTR lpProcName // 函数名称 ) ; 3) FreeLibrary 函数F r e e L i b r a r y动态地卸载动态链接库,并释放资源。原型如下: BOOL FreeLibrary( HMODULE hLibModule // DLL模块的句柄 ) ;
//用来测试插件的主窗体unit frmMain;interfaceuses Sharemem,Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Menus;const cPLUGIN_MASK='*.wd'; cPLUGIN_DESCRIBE='DescribePlugin'; cPLUGIN_INIT = 'InitPlugin';//定义插件的描述信息和后缀名 type TPluginDescribe = procedure(var Desc: string); stdcall; TPluginInit = procedure(ParentMenu: TMainMenu); stdcall; TForm1 = class(TForm) memPlugins: TMemo; mnuMain: TMainMenu; file1: TMenuItem; plus1: TMenuItem; procedure FormCreate(Sender: TObject); private { Private declarations } public procedure LoadPlugins; procedure LoadPlugin(sr: TSearchRec); end;var Form1: TForm1;implementation{$R *.dfm}procedure TForm1.LoadPlugin(sr: TSearchRec);//将插件的动态库读入 var Description: string; LibHandle: Integer; DescribeProc: TPluginDescribe; InitProc: TPluginInit; begin LibHandle := LoadLibrary(Pchar(sr.Name)); if LibHandle <> 0 then begin // 查找 DescribePlugin. DescribeProc := GetProcAddress(LibHandle, cPLUGIN_DESCRIBE); if Assigned(DescribeProc) then begin // 调用 DescribePlugin. DescribeProc(Description); memPlugins.Lines.Add(Description); // 查找 InitPlugin. InitProc := GetProcAddress(LibHandle, 'InitPlugin'); if Assigned(InitProc) then begin // 调用 InitPlugin. InitProc(mnuMain); end; end else begin MessageDlg('File "' + sr.Name + '" is not a valid plugin.', mtInformation, [mbOK], 0); end; end else begin MessageDlg('An error occurred loading the plugin "' + sr.Name + '".', mtInformation, [mbOK], 0); end; end; procedure TForm1.LoadPlugins;//查找插件 var sr: TSearchRec; path: string; Found: Integer; begin path := ExtractFilePath(Application.Exename); try Found := FindFirst(path + cPLUGIN_MASK, 0, sr); while Found = 0 do begin LoadPlugin(sr); Found := FindNext(sr); end; finally FindClose(sr); end; end; procedure TForm1.FormCreate(Sender: TObject); begin LoadPlugins; end;end.//插件的实现,新建一个DLL工程,工程代码入下 library Pplus2;{ Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. }uses Sharemem,//这里一定要加上 SysUtils, Classes, plus2 in 'plus2.pas';{$E wd}{$R *.res}exports DescribePlugin,InitPlugin;//导出函数begin end. //然后添加一个空白的文件,里面是插件的具体代码 unit plus2;
interfaceuses Dialogs, Menus,Classes;
type THolder = class public procedure ClickHandler(Sender: TObject); end;
1) LoadLibrary
函数L o a d L i b r a r y将D L L动态地装入内存。原型如下:
H I N S TANCE LoadLibrary(
LPCTSTR lpLibFileName // 指定模块所在的文件名
) ;
2) GetProcAddress
函数G e t P r o c A d d r e s s获取D L L中指定模块的地址。原型如下:
FARPROC GetProcAddress(
HMODULE hModule, // DLL模块的句柄
LPCSTR lpProcName // 函数名称
) ;
3) FreeLibrary
函数F r e e L i b r a r y动态地卸载动态链接库,并释放资源。原型如下:
BOOL FreeLibrary(
HMODULE hLibModule // DLL模块的句柄
) ;
Sharemem,Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Menus;const cPLUGIN_MASK='*.wd'; cPLUGIN_DESCRIBE='DescribePlugin'; cPLUGIN_INIT = 'InitPlugin';//定义插件的描述信息和后缀名
type
TPluginDescribe = procedure(var Desc: string); stdcall;
TPluginInit = procedure(ParentMenu: TMainMenu); stdcall;
TForm1 = class(TForm)
memPlugins: TMemo;
mnuMain: TMainMenu;
file1: TMenuItem;
plus1: TMenuItem;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public procedure LoadPlugins;
procedure LoadPlugin(sr: TSearchRec);
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.LoadPlugin(sr: TSearchRec);//将插件的动态库读入
var
Description: string; LibHandle: Integer; DescribeProc: TPluginDescribe;
InitProc: TPluginInit;
begin
LibHandle := LoadLibrary(Pchar(sr.Name));
if LibHandle <> 0 then
begin
// 查找 DescribePlugin.
DescribeProc := GetProcAddress(LibHandle,
cPLUGIN_DESCRIBE);
if Assigned(DescribeProc) then
begin
// 调用 DescribePlugin.
DescribeProc(Description);
memPlugins.Lines.Add(Description);
// 查找 InitPlugin.
InitProc := GetProcAddress(LibHandle, 'InitPlugin');
if Assigned(InitProc) then
begin
// 调用 InitPlugin.
InitProc(mnuMain);
end;
end else begin
MessageDlg('File "' + sr.Name +
'" is not a valid plugin.',
mtInformation, [mbOK], 0);
end;
end
else
begin
MessageDlg('An error occurred loading the plugin "' +
sr.Name + '".', mtInformation, [mbOK], 0);
end;
end;
procedure TForm1.LoadPlugins;//查找插件
var
sr: TSearchRec;
path: string;
Found: Integer;
begin
path := ExtractFilePath(Application.Exename);
try
Found := FindFirst(path + cPLUGIN_MASK, 0, sr);
while Found = 0 do begin
LoadPlugin(sr);
Found := FindNext(sr);
end;
finally
FindClose(sr);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
LoadPlugins;
end;end.//插件的实现,新建一个DLL工程,工程代码入下
library Pplus2;{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }uses
Sharemem,//这里一定要加上
SysUtils,
Classes,
plus2 in 'plus2.pas';{$E wd}{$R *.res}exports
DescribePlugin,InitPlugin;//导出函数begin
end.
//然后添加一个空白的文件,里面是插件的具体代码
unit plus2;
interfaceuses Dialogs, Menus,Classes;
type
THolder = class
public
procedure ClickHandler(Sender: TObject);
end;
procedure DescribePlugin(var Desc: string);
export; stdcall;
procedure InitPlugin(ParentMenu: TMainMenu);
export; stdcall;
var
Holder: THolder;
implementation
procedure DescribePlugin(var Desc: string);
begin
Desc := 'Test plugin 2 - Menu test';
end;
procedure InitPlugin(ParentMenu: TMainMenu);
var
i: TMenuItem;
begin
// 创建新菜单项.
{ NewItem('New item', TextToShortCut('Ctrl+N'),
False, True, Action1.OnExecute, 0, 'Item1') }
i := NewItem('Plugin &Test', scNone, False, True,Holder.ClickHandler, 0, 'mnuTest');
ParentMenu.Items[1].Add(i);
end;
procedure THolder.ClickHandler;
begin
ShowMessage('插件测试!');
end;
initialization
Holder := THolder.Create;
finalization
Holder.Free;
end.
这个差价就是返回一个描述插件信息,以及在主窗体上增加一个菜单
为了以一种易用的方式存储指向一个函数的指针,有必要为用到的变量创建一个特定的类型。注意,GetProcAddress的返回值被存储在一个变量中,DescribeProc,属于TpluginDescribe类型。下面是它的声明:
type
TPluginDescribe = procedure(var Desc: string); stdcall;
以及PluginInit,类型声明如下:
TPluginInit = procedure(ParentMenu: TMainMenu); stdcall;
由于过程存在于DLL内部,它通过标准调用转换编译所有导出例程,因此需要使用stdcall指示字。这个过程使用一个var参数,当过程返回的时候它包含插件的描述。
要调用刚刚获得的过程,只需要使用保存地址的变量作为过程名,后面跟上任何参数。就上面的例子而言,声明:
DescribeProc(Description)
将会调用在插件中获得的描述过程,并且用描述插件功能的字符串填充Description变量。