插件框架Extensible Framework for Delphi
工作需要开发的一套插件框架,给应用程序提供灵活的插件支持,基于Dll / Interface实现。
先上个图
这是个标准的基于插件的应用,下拉框里的就是由5个插件Dll提供的功能。主程序中定义了一个接口,而插件Dll则提供这个接口的实现。
使用也很简单,在窗口上放置一个TExtensionManager组件,设置一下插件的读取路径就可以了。
框架中有3个重要概念,ServiceHost,Module(模块)和扩展(Extension)
1.ServiceHost是整个框架的灵魂,不管是主程序中还是插件中,都通过他来查询和使用其他的插件对象。
下面是一段使用示例代码:(ServiceHost as ILoggingService).Log("This is a log");
(ServiceHost as IParameterService).SetValue("Param1", "Value1");
(ServiceHost as IMyPlugin).Foo();
(ServiceHost as IMyExtension).Execute();
2.Module是Extension的容器,即一个Module包含多个Extension。但实际上Module本身并不提供任何功能,也不提供Extension的管理功能,仅仅为Extension提供逻辑上的分组,同时为应用程序提供分组相关的信息。一个插件Dll中可以包含多个Module。
3.Extension是扩展对象管理类,当某个类实现了插件接口后,通过此对象对外发布,并由此对象管理其生命周期。
另外,框架里还提供了一些常用的服务,也是做为插件存在的,如上面的ILoggingService和IParameterService
IParameterService
参数服务,为应用程序和扩展提供参数支持,如 $(AppPath)
IRegistryService
注册表服务,用于信息储存和读取
ILoggingService
日志服务,通过信道将消息输出到不同的位置
IChannel
日志信道,用于将消息输出到指定的位置
ILocalizationService
本地化服务,用于提供本地化的资源
ILocaleSource
本地化服务数据源
ISplashService
闪屏服务,用于访问闪屏窗口
IDialogService
对话框服务,用于提供各种对话框
ILoginService
登录服务,用于控制用户登录
再贴几张Demo的图吧
示例代码:
unit uModule;
interface
implementation
uses
EFToolServices, EFModule, EFWinRegistry, EFLogging, EFParameter;
initialization
TInterfaceExtension.Create(IRegistryService, TWindowsRegistryService.Create,
'2011.08.11', 'RegistryService', 'IRegistryService Provider', 'Author: sephil');
TInterfaceExtension.Create(ILoggingService, TLoggingService.Create,
'2011.08.11', 'LoggingService', 'ILoggingService Provider', 'Author: sephil');
TInterfaceExtension.Create(IParameterService, TParameterService.Create,
'2011.08.11', 'ParameterService', 'IParameterService Provider', 'Author: sephil');
end.
unit uDllImpl;
interface
implementation
{$I EFDef.inc}
uses
EFExports, { export dll entry proc }
EFSystem, EFToolServices, EFModule, EFSysUtils,
uDocIntf, Windows, Messages, SysUtils;
type
TDllObject = class(TInterfacedObject, IDllObject)
private
procedure ExecOpen;
procedure ExecInsert(CanUndo: Boolean);
end;
TDllModule = class(TModule)
protected
class function InitializeComponents(Host: IInterface): Integer; override;
procedure UpdateDesctiption; override;
public
procedure Initialize; override;
procedure Finalize; override;
end;
{ TDllObject }
procedure TDllObject.ExecOpen;
var
S: WideString;
begin
(ServiceHost as IParameterService).GetValue('$(APPPATH)', S);
S := S + '\TextDoc.txt';
(ServiceHost as IDocument).Open(S);
end;
procedure TDllObject.ExecInsert(CanUndo: Boolean);
var
S: string;
begin
S := FormatDateTime('c', Now);
SendMessage((ServiceHost as IDocument).GetHWND,
EM_REPLACESEL, WPARAM(CanUndo), LPARAM(PChar(S)));
end;
{ TDllModule }
function GetModule: string;
begin
SetString(Result, nil, MAX_PATH);
SetLength(Result, GetModuleFileName(HInstance, @Result[1], MAX_PATH));
end;
class function TDllModule.InitializeComponents(Host: IInterface): Integer;
var
S: WideString;
begin
(ServiceHost as ILoggingService).Write('TDllModule.InitializeComponents');
(ServiceHost as IParameterService).GetValue('$(D2007)', S);
if {$IFDEF DELPHI12_UP}not{$ENDIF} StrToBool(S) then Result := 0 else Result := 1;
if Result <> 0 then
(ServiceHost as ILoggingService).Write(ExtractFileName(GetModule) + ' skipped')
else
(ServiceHost as ILoggingService).Write(ExtractFileName(GetModule) + ' loaded');
end;
procedure TDllModule.UpdateDesctiption;
begin
// original info from version info
inherited;
end;
procedure TDllModule.Initialize;
var
Intf: ILoggingService;
begin
inherited;
(ServiceHost as ILoggingService).Write('TDllModule.Initialize');
end;
procedure TDllModule.Finalize;
begin
inherited;
(ServiceHost as ILoggingService).Write('TDllModule.Finalize');
end;
initialization
RegisterModuleClass(TDllModule);
TExtensionFactory.Create(IDllObject, TDllObject, '2011.08.08',
'Dll Object', 'IDllObject implementation', 'Author: sephil');
end.