效果图如下,可以反复卸载和重新加载。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. selenium+chrome options

    selenium+chrome options 环境:selenium chrome 1.      selenium + chrome参数配置 1.1.    启动 from selenium im ...

  2. typescript 起步之安装及配置 ts-node 环境变量

    最近vue 3.0 版本发布,让我认识到 typescript 将占有越来越重要的地位,所以我也开启了typescript学习之旅. 要想编写第一个 hello typescript 程序,当然要经过 ...

  3. 关于and 和or的执行优先级问题分析

    题目:列出本店价低于60或者高于100.并且商品点击数大于628的商品. 按照下面两种写法,得到的结果是不同的. 第一种:结果数据中有点击数为628的记录,显然不符合题目要求. SELECTgoods ...

  4. git github 对代码的管理

    参考:https://www.cnblogs.com/feynman61/p/9005252.html 一.Git 对远程仓库版本回退 场景: 同事 a.b 同时修改了代码,提交到仓库 同时 c 不熟 ...

  5. Java基础 -4.2

    Switch分支语句 switch是一个开关语句,它主要是根据内容来进行判断的,需要注意的是switch中可以判断的只能够是数据(int.char.枚举.String)而不能够使用逻辑判断 publi ...

  6. Java基础 -2.4

    字符型char类型 在任何的编程语言之中,字符都可以与int进行互相转换,也就是这个字符中所描述的内容可以通过int获取其内容所在的系统编码 public class ddd { public sta ...

  7. 3_03_MSSQL课程_Ado.Net_登录复习和ExcuteScalar

    SQL注入 ->登陆窗体破解 ->配置文件 ->首先在 app.Config文件中添加 节点,如下: <connectionStrings> <add name=& ...

  8. web-pc项目中index页面分析

    先上HTML代码: <%@ page language="java" contentType="text/html; charset=UTF-8" pag ...

  9. python学习 —— 字符画

    代码: import os from PIL import Image WIDTH = int(250) HEIGHT = int(250/2) ascii_char = list('toahkbdp ...

  10. 获取Webshell方法总结

    一.CMS获取Webshell方法 搜索CMS网站程序名称 eg:phpcms拿webshell.wordpress后台拿webshell 二.非CMS获取Webshell方法 2.1数据库备份获取W ...