工作需要開發的一套外掛程式架構,給應用程式提供靈活的外掛程式支援,基於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
Log Service,通過通道將訊息輸出到不同的位置
IChannel
日誌通道,用於將訊息輸出到指定的位置
ILocalizationService
本地化服務,用於提供本地化的資源
ILocaleSource
本地化服務資料來源
ISplashService
閃屏服務,用於訪問閃屏視窗
IDialogService
對話方塊服務,用於提供各種對話方塊
ILoginService
登入服務,用於控制使用者登入
再貼幾張Demo的圖吧
範例程式碼:
View Code
// 主程式
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.
View Code
// 外掛程式
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.