惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Simon Willison's Weblog
Simon Willison's Weblog
G
Google Developers Blog
Spread Privacy
Spread Privacy
I
InfoQ
V
V2EX
S
Schneier on Security
小众软件
小众软件
C
CERT Recently Published Vulnerability Notes
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
L
Lohrmann on Cybersecurity
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Attack and Defense Labs
Attack and Defense Labs
云风的 BLOG
云风的 BLOG
The Hacker News
The Hacker News
S
SegmentFault 最新的问题
C
Cybersecurity and Infrastructure Security Agency CISA
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
Latest news
Latest news
S
Secure Thoughts
Project Zero
Project Zero
MongoDB | Blog
MongoDB | Blog
I
Intezer
Security Latest
Security Latest
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
N
Netflix TechBlog - Medium
V2EX - 技术
V2EX - 技术
量子位
T
Threatpost
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
T
Tor Project blog
A
Arctic Wolf
Microsoft Security Blog
Microsoft Security Blog
T
The Exploit Database - CXSecurity.com
大猫的无限游戏
大猫的无限游戏
T
Tailwind CSS Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
C
Check Point Blog
博客园 - Franky
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
The GitHub Blog
The GitHub Blog
L
LINUX DO - 热门话题

博客园 - Sephil

[小技巧] 倍数的向上取整和向下取整 WTL汉化版 Delphi 与 VC 共享接口和对象 DelphiXE泛型不能用类类型做为约束的另类解决方案 百度音乐下载工具 (最后更新: 2012-7-20) 为Delphi应用增加脚本支持 DirectUI for Delphi VC CListCtrl 第一列列宽自适应 WriteFile写磁盘扇区是87错误的原因 批量更改文件名的批处理文件 替代Windows运行功能的工具FastRun 关于 API 中返回字串的一些问题 BCB/Delphi2007 隐藏任务栏图标 OGA & WGA Crack 所有小工具 迅雷/快车/旋风地址转换器 oracle ora-01033和ora-00600错误 数独游戏 SudokuPuzzle 将文件夹映射为驱动器的工具
插件框架Extensible Framework for Delphi
Sephil · 2012-02-22 · via 博客园 - Sephil

工作需要开发的一套插件框架,给应用程序提供灵活的插件支持,基于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的图吧

示例代码:

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.