这个DEMO中主要是在DLL中建立了一个IDockableControl类,并在DLL的子类中写了具体的实现方法。

在主程序exe中,找到这个服务,然后调用DLL的内嵌方法,把DLL插件窗口内嵌到主程序中。

界面如下

DLL代码如下:

unit Frm_Dll;

interface

uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
qstring,
QPlugins,
Vcl.Imaging.jpeg,
Vcl.ExtCtrls,
Vcl.StdCtrls,
Vcl.AxCtrls,
qplugins_base,
qplugins_vcl_messages; type
TForm_Dll = class(TForm)
Panel1: TPanel;
Button1: TButton;
CheckBox1: TCheckBox;
Edit1: TEdit;
Edit2: TEdit;
Image1: TImage;
Label1: TLabel;
private
{ Private declarations }
protected
procedure CreateParams(var Params: TCreateParams); override;
public { Public declarations }
end; // 创建一个接口,方法都由子类来实现
IDockableControl = interface
['{D0A4BDFA-CB29-4725-9158-C199B9C373C9}']
procedure DockTo(AHandle: HWND); stdcall;
procedure HostSizeChanged; stdcall;
end; // 接口方法的类
TDockableService = class(TQService, IDockableControl)
protected
FForm: TForm;
procedure DockTo(AHandle: HWND); stdcall;
procedure HostSizeChanged; stdcall;
public
constructor Create(const AId: TGuid; AName: QStringW); overload; override;
destructor Destroy; override;
end; TDockInstanceService = class(TQService)
public
function GetInstance: IQService; override; stdcall;
end; var
Form_Dll: TForm_Dll; implementation {$R *.dfm}
{ TDockableService } constructor TDockableService.Create(const AId: TGuid; AName: QStringW);
begin
// 继承
inherited Create(AId, AName);
end; // 销毁
destructor TDockableService.Destroy;
begin
FreeAndNil(FForm);
inherited;
end; // 内嵌窗口
procedure TDockableService.DockTo(AHandle: HWND);
begin
// 创建窗体
FForm := TForm_Dll.Create(nil);
FForm.BorderStyle := bsNone;
FForm.ParentWindow := AHandle;
FForm.DoubleBuffered := True;
FForm.Show;
// 设置窗口大小
HostSizeChanged;
end; procedure TDockableService.HostSizeChanged;
var
R: TRect;
begin
// 取父窗口大小
GetClientRect(Winapi.Windows.GetParent(FForm.Handle), R);
// 设置子窗口大小
FForm.SetBounds(, , R.Width, R.Height);
end; { TDockInstanceService } function TDockInstanceService.GetInstance: IQService;
begin
Result := TDockableService.Create(NewId, 'DockableService');
end; { TForm2 } procedure TForm_Dll.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style and (not(WS_CAPTION or WS_THICKFRAME));
// 不要标题和边框,实际上就是 BorderStyle 为 bsNone 的效果
end; initialization // 注册 /Services/Docks/Frame 服务
RegisterServices('Services/Docks', [TDockInstanceService.Create(IDockableControl, 'Frame')]); finalization // 取消服务注册
UnregisterServices('Services/Docks', ['Frame']); end.

EXE代码如下

unit Frm_Main;

interface

{
VCL DLL或主程序需要引用 QPlugins.VCL 单元,该单元实现了替代的消息处理和派发
}
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.ComCtrls,
Vcl.StdCtrls,
Vcl.ExtCtrls,
QPlugins,
QPlugins_loader_lib,
QPlugins_Vcl_Messages; type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
PageControl1: TPageControl;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure PageControl1Resize(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; // DLL中的接口,方法都由DLL的子类来实现
IDockableControl = interface
['{D0A4BDFA-CB29-4725-9158-C199B9C373C9}']
procedure DockTo(AHandle: HWND); stdcall;
procedure HostSizeChanged; stdcall;
end; // 加强的Tabsheet
TDockHostPage = class(TTabSheet)
private
procedure SetDockedControl(const Value: IDockableControl);
protected
FDockedControl: IDockableControl;
public
property DockedControl: IDockableControl read FDockedControl write SetDockedControl;
end; var
Form1: TForm1; implementation {$R *.dfm} // 按钮_新页
procedure TForm1.Button1Click(Sender: TObject);
var
ACtrl: IDockableControl;
ATabSheet: TDockHostPage;
begin
// 根据'Services/Docks/Frame'找到DLL中的TDockInstanceService服务
ACtrl := PluginsManager.ByPath('Services/Docks/Frame') as IDockableControl;
// 如果这个服务存在
if Assigned(ACtrl) then
begin
// 创建一个加强的Tabsheet,并把DLL中的TDockInstanceService服务内嵌进去
ATabSheet := TDockHostPage.Create(PageControl1);
ATabSheet.PageControl := PageControl1;
ATabSheet.Caption := '第 ' + IntToStr(PageControl1.PageCount) + ' 页';
ATabSheet.DockedControl := ACtrl;
// 激活
PageControl1.ActivePage := ATabSheet;
end
else
begin
Application.MessageBox('Services/Docks/Frame 服务未注册,请编译DLL先。', '服务未注册', MB_OK or MB_ICONSTOP);
end;
end; // 创建
procedure TForm1.FormCreate(Sender: TObject);
var
APath: string;
begin
ReportMemoryLeaksOnShutdown := True;
APath := ExtractFilePath(Application.ExeName);
// 注册默认的 DLL 加载器,扩展名可以根据实际的情况随意修改,多个扩展名之间用逗号或分号分隔
PluginsManager.Loaders.Add(TQDLLLoader.Create(APath, '.dll'));
// 启动插件注册,如果要显示加载进度,可以注册IQNotify响应函数响应进度通知
PluginsManager.Start;
end; // 窗口大小调整
procedure TForm1.PageControl1Resize(Sender: TObject);
var
I: Integer;
APage: TDockHostPage;
begin
// 遍历窗体
for I := to PageControl1.PageCount - do
begin
APage := PageControl1.Pages[I] as TDockHostPage;
if APage.DockedControl <> nil then
begin
APage.DockedControl.HostSizeChanged;
end;
end;
end; { TDockHostPage } // 接口作为参数传过来就内嵌到加强的Tabsheet中
procedure TDockHostPage.SetDockedControl(const Value: IDockableControl);
begin
if FDockedControl <> Value then
begin
FDockedControl := Value;
if Assigned(Value) then
begin
// DLl中的内嵌窗口函数
Value.DockTo(Handle);
end;
end;
end; end.

012.Delphi插件之QPlugins,多实例内嵌窗口服务的更多相关文章

  1. 013.Delphi插件之QPlugins,模块化代码示例

    这个DEMO的是一个定义了一个窗体插件接口,把其他窗口注册到这个窗体插件接口中.主程序运行起来,就遍历一下窗体插件接口,把每个窗体内嵌到对话框中 运行效果如下 主窗口代码如下 unit Frm_Mai ...

  2. 015.Delphi插件之QPlugins,FMX插件窗口

    内嵌FMX的插件窗口,效果还是很可以的.退出时,会报错,很诡异啊. 主窗口代码如下 unit Frm_Main; interface uses Winapi.Windows, Winapi.Messa ...

  3. 004.Delphi插件之QPlugins,参数传递

    界面如下 插件框架中大量使用了接口的东西,看的眼花缭乱,很多地方只做了申明,具体的实现是在另外的子类. DLL的代码如下 unit ParamTest; interface uses classes, ...

  4. WPF内嵌WCF服务对外提供接口

    要测试本帖子代码请记得管理员权限运行vs. 我写这个帖子的初衷是在我做surface小车的时候有类似的需求,感觉这个功能还挺有意思的,所以就分享给大家,网上有很多关于wcf的文章 我就不一一列举了.公 ...

  5. 014.Delphi插件之QPlugins,MDI窗口

    不知道为什么,这个DEMO编译出来报错,运行不了,在QDAC群里问了一下也没人响应. 效果如下 主程序代码如下 unit Frm_Main; interface uses Winapi.Windows ...

  6. 011.Delphi插件之QPlugins,延时加载服务

    这个DEMO是是把DLL插件的相关信息做成了一个配置文件,主程序加载这个配置文件,从而起到延时加载的作用 主程序代码如下 unit Frm_Main; interface uses Winapi.Wi ...

  7. 010.Delphi插件之QPlugins,遍历服务接口

    这个DEMO注意是用来看一个DLL所拥有的全部服务接口 演示效果如下 代码如下: unit Frm_Main; interface uses Winapi.Windows, Winapi.Messag ...

  8. 009.Delphi插件之QPlugins,服务的热插拔

    这个DEMO用来演示服务的替换,用起来总是怪怪的感觉,效果图如下 代码如下 unit Frm_Main; interface uses Winapi.Windows, Winapi.Messages, ...

  9. 007.Delphi插件之QPlugins,插件的卸载和重新加载

    效果图如下,可以反复卸载和重新加载.QPlugins这个插件,还没弄明白,摸索着跟着DEMO写 主窗口代码如下 unit Frm_Main; interface uses Winapi.Windows ...

随机推荐

  1. 牛茶冲天的ip命令

    一.修改二层链路相关设置 1.修改网卡名称(修改前要先停止) ip link set eth0 name  testname 2.修改网卡地址 ip link set eth0 address xxx ...

  2. 二十一 Struts的数据校验两种方式:手动编码和xml校验

    数据的校验: 一.前台校验:JS校验 JS的校验不是必须的,JS可以被绕行,可以提升用户体验 二.后台校验:编码校验 必须的校验 三.校验的方式: 手动编码(不建议使用) 配置文件(支持) 手动编码的 ...

  3. 夯实Java基础(二十二)——Java8新特性之Lambda表达式

    1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...

  4. mybaits requestMap与requestType,以及对应的注解

    有的时候不喜欢用xml配置文件,但是xml配置文件的开发使用简单,自己经常要用到: 因为代码维护的缘故,有的时候看别人的代码,可能存在大量的mappper文件,也不是你想用注解就用注解的: 下面我还是 ...

  5. 动态设置WX滚动条的高度(非常重要)

    wxml: <scroll-view class="scroll" scroll-y="true" style="height:{{client ...

  6. MD5摘要

    MD5简介 MD5即Message-Digest Algorithm 5(信息-摘要算法),属于摘要算法,是一个不可逆过程,就是无论多大数据,经过算法运算后都是生成固定长度的数据,结果使用16进制进行 ...

  7. C# String 字符串一些关键理解

    #1 :在.Net Framework中,字符总是表示成16位Unicode的代码#2 :String 和string 其实是一样的只是表现形式上不同#3 :string类型被视为基元类型,也就是编译 ...

  8. A easy and simple way to establish Oracle ADG

    Yes, thanks to Then, I can give simple and reasy way to make it. Suppose hosts and IPs like that: 15 ...

  9. 1-Docker学习笔记

    docker还是比较容易的,比较蛋疼的就是镜像网络问题,不过也可以配置了镜像加速器(比如阿里云).这里重点记录一下初学docker时遇到的知识点. docker环境变量 docker对环境变量的定义和 ...

  10. KMP(模板)

    kmp算法是解决单模匹配问题的算法,难点在于求next[]数组 求next[]数组:对于模板串的所有前缀子串的最长公共前后缀的长度,就是next[]数组的值 eg:主串为cbbbaababac  子串 ...