效果图如下,可以反复卸载和重新加载。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. GO闭包

    package main import "fmt" func main() { add_func := add(1,2) fmt.Println(add_func(1,1)) fm ...

  2. STM32 RTC上的唤醒和闹钟

    RTC很简单只要给备用电,RTC就会不停,可以进行设置和读时间.同时在RTC上也涉及了闹钟(EXTI_17:RTC_FLAG_ALRAF,相当于RTC的定时器,闹钟到了之后进行异步操作)和唤醒中断(低 ...

  3. eclipse导入项目上面有个红叉X

    问题: 今天突然想到一个以前做过的项目,想导入到新环境中,发现不管咱整都一个红叉X, 我记得以前好像碰到过类似的问题,当时三秒搞定,谁知道时间一长,三分钟没有搞定. 还是记录下: 一般导入项目出错,肯 ...

  4. Android。WebView加载UR请求使用Cookie储存User_Id记录用户是否登陆过

    1.WebView初始化的时候用倒如下代码: if (Build.VERSION.SDK_INT >= 21) { CookieManager.getInstance().setAcceptTh ...

  5. 数学公式在 iOS 中的表示

    1. 三角函数  double sin (double);正弦  double cos (double);余弦  double tan (double);正切 2 .反三角函数  double asi ...

  6. node.js绑定监听事件EventEmitter类

    Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下: // 引入 events 模块 var events = r ...

  7. php实现简单链式操作mysql数据库类

    <?php $dbConfig = require_once(dirname(__FILE__).'/config.php'); class Db{     public $conn;      ...

  8. redis 之redis持久化rdb与aof

    redis是内存型的数据库 重启服务器丢失数据 重启redis服务丢失数据 断电丢失数据 Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题,Redis提供了两种 ...

  9. 109、Java中String类之截取部分子字符串

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  10. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:清除浮动

    <!DOCTYPE html> <html> <head> <title>Bootstrap .clearfix 实例</title> &l ...