007.Delphi插件之QPlugins,插件的卸载和重新加载
效果图如下,可以反复卸载和重新加载。QPlugins这个插件,还没弄明白,摸索着跟着DEMO写


主窗口代码如下
unit Frm_Main; interface uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.StdCtrls,
Vcl.ExtCtrls,
QPlugins,
qplugins_base,
qplugins_params,
qplugins_loader_lib,
Vcl.ComCtrls,
qplugins_formsvc,
qplugins_vcl_formsvc; { 要安全的移除一项服务,则使用该服务的模块必需实现IQNotify接口,并对NID_PLUGIN_UNLOADING
通知的响应,并在通知里移除掉到服务的引用,以便插件能够被安全的释放。 如果需要在某个插件注册后,引用某项服务,可以响应NID_PLUGIN_LOADED通知,在其中查询新的
服务实例并记录它
}
type
TForm_Main = class(TForm, IQNotify)
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
mmLogs: TMemo;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
// 服务接口
FHoldService: IQService;
// 在通知发生时,通知响应函数接口。IQNotify接口中定义的函数,子类来实现这个函数
procedure Notify(const AId: Cardinal; AParams: IQParams; var AFireNext: Boolean); stdcall;
public
{ Public declarations }
end; var
Form_Main: TForm_Main; implementation {$R *.dfm} // 按钮_重新加载
procedure TForm_Main.Button1Click(Sender: TObject);
var
AFileName: string;
ALoader: IQLoader;
begin
// DLL插件的全名
AFileName := ExtractFilePath(Application.ExeName) + '插件.dll';
// 如果DLL文件存在
if FileExists(AFileName) then
begin
// ByPath通过路径获取指定的服务接口实例
ALoader := PluginsManager.ByPath('/Loaders/Loader_DLL') as IQLoader;
if Assigned(ALoader) then
begin
// 加载服务
ALoader.LoadServices(PWideChar(AFileName));
end;
end;
end; // 按钮_卸载插件
procedure TForm_Main.Button2Click(Sender: TObject);
var
AModule: HMODULE;
ALoader: IQLoader;
// 取服务模块
function ServiceModule: HMODULE;
begin
if Assigned(FHoldService) then
Result := FHoldService.GetOwnerInstance
else
begin
Result := ;
end;
end; begin
// 取服务模块
AModule := ServiceModule;
// 如果模块存在
if AModule <> then
begin
// 通过路径获取指定的服务接口实例
ALoader := PluginsManager.ByPath('/Loaders/Loader_DLL') as IQLoader;
if Assigned(ALoader) then
begin
// 卸载这个服务
ALoader.UnloadServices(AModule);
end;
end;
end; // 按钮_显示窗体
procedure TForm_Main.Button3Click(Sender: TObject);
var
// 窗体服务的接口
AFormService: IQFormService;
begin
// 获取指定路径的服务实例(如果是多实例,则返回一个用于提供服务的新实例)
if GetService('Services/Forms/DynamicLoadForm', IQFormService, AFormService) then
begin
// 嵌入窗体到父窗口的特定的位置
AFormService.DockTo(TabSheet2.Handle, faContent);
end;
end; // 创建
procedure TForm_Main.FormCreate(Sender: TObject);
begin
//
with PluginsManager as IQNotifyManager do
begin
// Subscribe订阅通知
Subscribe(NID_PLUGIN_LOADING, Self);
Subscribe(NID_PLUGIN_UNLOADING, Self);
Subscribe(NID_PLUGIN_LOADED, Self);
end;
// 加载同目录DLL
PluginsManager.Loaders.Add(TQDLLLoader.Create(ExtractFilePath(Application.ExeName), '.dll'));
// 启动所有的加载器加载支持的插件
PluginsManager.Start;
end; // 销毁
procedure TForm_Main.FormDestroy(Sender: TObject);
begin
with PluginsManager as IQNotifyManager do
begin
// 取消订阅通知
Unsubscribe(NID_PLUGIN_LOADING, Self);
Unsubscribe(NID_PLUGIN_UNLOADING, Self);
Unsubscribe(NID_PLUGIN_LOADED, Self);
end;
end; // 在通知发生时,通知响应函数接口。IQNotify接口中定义的函数,子类来实现这个函数
procedure TForm_Main.Notify(const AId: Cardinal; AParams: IQParams; var AFireNext: Boolean);
var
AParam: IQParam;
begin
if Assigned(AParams) then
begin
// 根据传入的参数,进行不同的输出
case AId of
// 加载
NID_PLUGIN_LOADING:
begin
// 取DLL插件全路径
AParam := AParams.ByName('File');
mmLogs.Lines.Add('正在加载插件 ' + ParamAsString(AParam) + ' ...');
end;
// 加载完成
NID_PLUGIN_LOADED:
begin
// 服务接口赋值
FHoldService := PluginsManager.ByPath('Services/HoldService');
if Assigned(FHoldService) then
begin
mmLogs.Lines.Add('HoldService 已经成功加载');
end;
end;
// 卸载
NID_PLUGIN_UNLOADING:
begin
// 取DLL插件全路径
AParam := AParams.ByName('Instance');
if Assigned(AParam) and (FHoldService.GetOwnerInstance = AParam.AsInt64) then
begin
FHoldService := nil;
AParam := AParams.ByName('File');
mmLogs.Lines.Add('正在卸载插件' + ParamAsString(AParam) + ',移除关联服务 ...');
end;
end;
end;
end;
end; end.
DLL的界面代码如下
unit Frm_Dll; interface uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
QPlugins,
qplugins_vcl_formsvc,
Vcl.StdCtrls; type
TForm_Dll = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; var
Form_Dll: TForm_Dll; implementation {$R *.dfm} // 按钮_卸载服务
procedure TForm_Dll.Button1Click(Sender: TObject);
begin
// 卸载服务
UnloadServices(HInstance, False);
end; initialization // 初始化时,加载插件
RegisterFormService('Services/Forms', 'DynamicLoadForm', TForm_Dll, False); finalization // 卸载插件
UnregisterServices('Services/Forms', ['DynamicLoadForm']); end.
自带了一个pas文件,不知道是干嘛用的
unit holdservice; interface uses
qstring,
qplugins,
qplugins_params; type
// 这个只是用来测试,实际上什么也不干
THoldService = class(TQService)
end; implementation initialization // 注册
RegisterServices('/Services', [THoldService.Create(NewId, 'HoldService')]); finalization // 注销
UnregisterServices('/Services', ['HoldService']); end.
007.Delphi插件之QPlugins,插件的卸载和重新加载的更多相关文章
- IDEA下利用Jrebel插件实现JFinal项目main方法【热加载】
IDEA下利用Jrebel插件实现JFinal项目main方法[热加载] Jrebel破解办法 https://github.com/ilanyu/ReverseProxy/releases/tag/ ...
- 利用MEF实现插件机制(可根据输入类型来加载特定dll)
最近在做PACS的项目中想利用插件来加载各个不同的SCP的操作实现.比如Worklist的查询数据库,可以有多个实现. 比如MPPS的更新,也可以有多个实现. 为了统一弹性处理插件模块,增加了类型输入 ...
- H5页面基于iScroll.js插件实现下拉刷新,上拉加载更多
前言 在我之前的项目中,页面总是干巴巴的,用户的体验不是特别完美,我也是一直觉得把设计师给到的psd做出来就好,很少考虑用户的感受.我喜欢看不同的App,操作每个步骤,观赏每个能和我互动的交互设计效果 ...
- 基于.NET MVC的高性能IOC插件化架构(二)之插件加载原理
上一篇博文简单介绍了下插件化的代码组成部分:http://www.cnblogs.com/gengzhe/p/4390932.html,源码地址:https://github.com/luohuazh ...
- Qt插件热加载-QPluginLoader实现
上一篇C++消息框架-基于sigslot文章中我们讲述了使用sigslot信号槽实现自己的消息框架,这是一个比较粗糙,而且小的框架.当我们的程序逐渐变大时,我们可能就会考虑功能插件化,或者支持某些模块 ...
- 使用 .NET Core 3.0 的 AssemblyLoadContext 实现插件热加载
一般情况下,一个 .NET 程序集加载到程序中以后,它的类型信息以及原生代码等数据会一直保留在内存中,.NET 运行时无法回收它们,如果我们要实现插件热加载 (例如 Razor 或 Aspx 模版的热 ...
- 使用jOrgChart插件, 异步加载生成组织架构图
jOrgChart插件是一个用来实现组织结构图的Jquery的插件- 一.特点 1.支持拖拽修改子节点: 2.支持节点缩放展示: 3.方便修改css定义样式: 4.超轻量型: 5.兼容性好,基本支持所 ...
- 集成iscroll 下拉加载更多 jquery插件
一个插件总是经过了数月的沉淀,不断的改进而成的.最初只是为了做个向下滚动,自动加载的插件.随着需求和功能的改进,才有了今天的这个稍算完整的插件. 一.插件主功能: 1.下拉加载 2.页面滚动到底部自动 ...
- 在NPAPI开发火狐浏览器插件在NPAPI插件
1.插件是什么 插件是一种遵循一定规范的应用程序接口编写出来的程序.插件必须依附于一个宿主程序,为宿主程序提供增强功能.插件的种类有很多,这里主要讨论浏览器插件. IE下利用OLE和COM技术开发的浏 ...
随机推荐
- CentOS使用日常
安装Teamview TeamViewer官网 下载rpm包 yum install -y teamviewer.x86_64.rpm 搞定 systemctl status firewalld #查 ...
- Balanced Lineup -POJ3264
题意: 告诉你n头奶牛的高度,然后给你一个区间,你需要求出这个区间最高的奶牛与最矮的奶牛之间相差多少 链接:http://poj.org/problem?id=3264 思路: 线段树区间查询,用两个 ...
- AI基础概念
基础概念 epoch:使用训练的全部数据对模型进行一次完整的训练,被成为“一代训练”.当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一次epoch.(也就是说,所有训练样本在神经网络 ...
- c++继承:公有、私有、保护(对应p12访问限制)
公有继承(public).私有继承(private).保护继承(protected)是常用的三种继承方式. 1. 公有继承(public) 公有继承的特点是基类的公有成员和保护成员作为派生类的成员时, ...
- Linux 下面搭建KMS服务器
1. 下载安装Linux 版的KMS服务软件 # wget https://github.com/Wind4/vlmcsd/releases/download/svn1111/binaries.tar ...
- Linux centosVMware xshell使用xftp传输文件、使用pure-ftpd搭建ftp服务
一.xshell使用xftp传输文件 Ctrl+Alt+F 弹出 下载进入 填写任意名字,自己邮箱 进入邮箱点击网址就自动下载了 然后安装 二.使用pure-ftpd搭建ftp服务 yum insta ...
- redis服务器性能优化
1.系统内存OOM优化 vm.overcommit_memory Redis会占用非常大内存,所以通常需要关闭系统的OOM,方法为将“/proc/sys/vm/overcommit_memory”的值 ...
- 从零开始编写IntelliJ IDEA插件
写Java代码的时候,经常会涉及到重复性的操作,这个时候就会想要是有这样一个插件就好了,如果是大家都会遇到的场景,IDE或许已经提供了,再不然也有可能有人编写了相关的插件.要是这个操作是你们的编码环境 ...
- SQLite、MySQL和PostgreSQL 三种关系数据库哪个好?
关系型数据库的使用已经有相当长的时间了.它们变得流行起来托了管理系统的福,关系模型被实现得相当的好,并且被证明是操作数据的好方法(特别是事务性强的应用). 在这篇DigitalOcean文章中,我们将 ...
- 吴裕雄--天生自然HADOOP学习笔记:hadoop集群实现PageRank算法实验报告
实验课程名称:大数据处理技术 实验项目名称:hadoop集群实现PageRank算法 实验类型:综合性 实验日期:2018年 6 月4日-6月14日 学生姓名 吴裕雄 学号 15210120331 班 ...