效果图如下,可以反复卸载和重新加载。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,插件的卸载和重新加载的更多相关文章

  1. IDEA下利用Jrebel插件实现JFinal项目main方法【热加载】

    IDEA下利用Jrebel插件实现JFinal项目main方法[热加载] Jrebel破解办法 https://github.com/ilanyu/ReverseProxy/releases/tag/ ...

  2. 利用MEF实现插件机制(可根据输入类型来加载特定dll)

    最近在做PACS的项目中想利用插件来加载各个不同的SCP的操作实现.比如Worklist的查询数据库,可以有多个实现. 比如MPPS的更新,也可以有多个实现. 为了统一弹性处理插件模块,增加了类型输入 ...

  3. H5页面基于iScroll.js插件实现下拉刷新,上拉加载更多

    前言 在我之前的项目中,页面总是干巴巴的,用户的体验不是特别完美,我也是一直觉得把设计师给到的psd做出来就好,很少考虑用户的感受.我喜欢看不同的App,操作每个步骤,观赏每个能和我互动的交互设计效果 ...

  4. 基于.NET MVC的高性能IOC插件化架构(二)之插件加载原理

    上一篇博文简单介绍了下插件化的代码组成部分:http://www.cnblogs.com/gengzhe/p/4390932.html,源码地址:https://github.com/luohuazh ...

  5. Qt插件热加载-QPluginLoader实现

    上一篇C++消息框架-基于sigslot文章中我们讲述了使用sigslot信号槽实现自己的消息框架,这是一个比较粗糙,而且小的框架.当我们的程序逐渐变大时,我们可能就会考虑功能插件化,或者支持某些模块 ...

  6. 使用 .NET Core 3.0 的 AssemblyLoadContext 实现插件热加载

    一般情况下,一个 .NET 程序集加载到程序中以后,它的类型信息以及原生代码等数据会一直保留在内存中,.NET 运行时无法回收它们,如果我们要实现插件热加载 (例如 Razor 或 Aspx 模版的热 ...

  7. 使用jOrgChart插件, 异步加载生成组织架构图

    jOrgChart插件是一个用来实现组织结构图的Jquery的插件- 一.特点 1.支持拖拽修改子节点: 2.支持节点缩放展示: 3.方便修改css定义样式: 4.超轻量型: 5.兼容性好,基本支持所 ...

  8. 集成iscroll 下拉加载更多 jquery插件

    一个插件总是经过了数月的沉淀,不断的改进而成的.最初只是为了做个向下滚动,自动加载的插件.随着需求和功能的改进,才有了今天的这个稍算完整的插件. 一.插件主功能: 1.下拉加载 2.页面滚动到底部自动 ...

  9. 在NPAPI开发火狐浏览器插件在NPAPI插件

    1.插件是什么 插件是一种遵循一定规范的应用程序接口编写出来的程序.插件必须依附于一个宿主程序,为宿主程序提供增强功能.插件的种类有很多,这里主要讨论浏览器插件. IE下利用OLE和COM技术开发的浏 ...

随机推荐

  1. pymongo 用户密码连接

    # db mongodbdb_mongo_attr = { 'host': '*', 'port': 27, 'database':'tease', 'username':'*v', 'passwor ...

  2. MFC TreeControl简单应用

    目录 1. TreeControl添加节点 2. TreeControl菜单 3. TreeControl修改节点 4. TreeControl查找节点 5. TreeControl折叠展开节点 6. ...

  3. [蓝桥杯2015初赛]生命之树(树状dp)

    在X森林里,上帝创建了生命之树.他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值.上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都存在一个点列 ...

  4. android传递数据bundle封装传递map对象

    android开发默认情况下,通过Bundle bundle=new Bundle();传递值是不能直接传递map对象的,解决办法: 第一步:封装自己的map,实现序列化即可 ? 1 2 3 4 5 ...

  5. 解题报告:luogu P1196 [NOI2002]银河英雄传说

    由于并查集让我很自闭(其实是我太弱了),所以学习了加权并查集,这是例题: 题目链接:P1196 [NOI2002]银河英雄传说 不是很简单,但对于大佬还是签到题. 合并与路径压缩时直接维护\(dis[ ...

  6. Mysql ,用户管理命令

    添加用户.删除用户与授权以下对数据库的操作完全可以利用管理软件完成,比如在Navicat上进行操作,对数据库进行用户和权限管理. 1.创建用户:以root用户登录到数据库进行用户创建 命令: CREA ...

  7. requests---requests封装请求类型

    我们在做自动化的时候,肯定是代码越简洁越好,代码重复量越少越好,这里呢,我们可以通过把requests的请求类型都封装起来,这样编写用例的时候可以直接进行请求 requests方法封装 我们通常用的最 ...

  8. 清除编译缓存DerivedDate

    当多次重构工程造成代码没有错误却编译失败时,可以尝试删除DerivedData目录.DerivedData目录是Xcode的编译缓存,路径是~/Library/Developer/Xcode/Deri ...

  9. web阶段乱码问题

    一,概述 1.为什么会出现乱码问题 因为客户端(浏览器)和服务器端的编码和解码不一致. 我们web阶段都是围绕请求响应机制展开的, 客户端请求服务器,服务器给客户端做出响应 . 也就意味着客户端和服务 ...

  10. 题解:luogu P3909

    这个题拖了快三个月了,只因缺个快速乘(气愤.jpg). 题目链接:P3909 异或之积 你确定没人用前缀和,后缀和吗? 蒟蒻想法与众不同! 我们实验\(A[]={1,2,3,4}\). 这里计不乘6时 ...