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

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

界面如下

DLL代码如下:

  1. unit Frm_Dll;
  2.  
  3. interface
  4.  
  5. uses
  6. Winapi.Windows,
  7. Winapi.Messages,
  8. System.SysUtils,
  9. System.Variants,
  10. System.Classes,
  11. Vcl.Graphics,
  12. Vcl.Controls,
  13. Vcl.Forms,
  14. Vcl.Dialogs,
  15. qstring,
  16. QPlugins,
  17. Vcl.Imaging.jpeg,
  18. Vcl.ExtCtrls,
  19. Vcl.StdCtrls,
  20. Vcl.AxCtrls,
  21. qplugins_base,
  22. qplugins_vcl_messages;
  23.  
  24. type
  25. TForm_Dll = class(TForm)
  26. Panel1: TPanel;
  27. Button1: TButton;
  28. CheckBox1: TCheckBox;
  29. Edit1: TEdit;
  30. Edit2: TEdit;
  31. Image1: TImage;
  32. Label1: TLabel;
  33. private
  34. { Private declarations }
  35. protected
  36. procedure CreateParams(var Params: TCreateParams); override;
  37. public
  38.  
  39. { Public declarations }
  40. end;
  41.  
  42. // 创建一个接口,方法都由子类来实现
  43. IDockableControl = interface
  44. ['{D0A4BDFA-CB29-4725-9158-C199B9C373C9}']
  45. procedure DockTo(AHandle: HWND); stdcall;
  46. procedure HostSizeChanged; stdcall;
  47. end;
  48.  
  49. // 接口方法的类
  50. TDockableService = class(TQService, IDockableControl)
  51. protected
  52. FForm: TForm;
  53. procedure DockTo(AHandle: HWND); stdcall;
  54. procedure HostSizeChanged; stdcall;
  55. public
  56. constructor Create(const AId: TGuid; AName: QStringW); overload; override;
  57. destructor Destroy; override;
  58. end;
  59.  
  60. TDockInstanceService = class(TQService)
  61. public
  62. function GetInstance: IQService; override; stdcall;
  63. end;
  64.  
  65. var
  66. Form_Dll: TForm_Dll;
  67.  
  68. implementation
  69.  
  70. {$R *.dfm}
  71. { TDockableService }
  72.  
  73. constructor TDockableService.Create(const AId: TGuid; AName: QStringW);
  74. begin
  75. // 继承
  76. inherited Create(AId, AName);
  77. end;
  78.  
  79. // 销毁
  80. destructor TDockableService.Destroy;
  81. begin
  82. FreeAndNil(FForm);
  83. inherited;
  84. end;
  85.  
  86. // 内嵌窗口
  87. procedure TDockableService.DockTo(AHandle: HWND);
  88. begin
  89. // 创建窗体
  90. FForm := TForm_Dll.Create(nil);
  91. FForm.BorderStyle := bsNone;
  92. FForm.ParentWindow := AHandle;
  93. FForm.DoubleBuffered := True;
  94. FForm.Show;
  95. // 设置窗口大小
  96. HostSizeChanged;
  97. end;
  98.  
  99. procedure TDockableService.HostSizeChanged;
  100. var
  101. R: TRect;
  102. begin
  103. // 取父窗口大小
  104. GetClientRect(Winapi.Windows.GetParent(FForm.Handle), R);
  105. // 设置子窗口大小
  106. FForm.SetBounds(, , R.Width, R.Height);
  107. end;
  108.  
  109. { TDockInstanceService }
  110.  
  111. function TDockInstanceService.GetInstance: IQService;
  112. begin
  113. Result := TDockableService.Create(NewId, 'DockableService');
  114. end;
  115.  
  116. { TForm2 }
  117.  
  118. procedure TForm_Dll.CreateParams(var Params: TCreateParams);
  119. begin
  120. inherited;
  121. Params.Style := Params.Style and (not(WS_CAPTION or WS_THICKFRAME));
  122. // 不要标题和边框,实际上就是 BorderStyle 为 bsNone 的效果
  123. end;
  124.  
  125. initialization
  126.  
  127. // 注册 /Services/Docks/Frame 服务
  128. RegisterServices('Services/Docks', [TDockInstanceService.Create(IDockableControl, 'Frame')]);
  129.  
  130. finalization
  131.  
  132. // 取消服务注册
  133. UnregisterServices('Services/Docks', ['Frame']);
  134.  
  135. end.

EXE代码如下

  1. unit Frm_Main;
  2.  
  3. interface
  4.  
  5. {
  6. VCL DLL或主程序需要引用 QPlugins.VCL 单元,该单元实现了替代的消息处理和派发
  7. }
  8. uses
  9. Winapi.Windows,
  10. Winapi.Messages,
  11. System.SysUtils,
  12. System.Variants,
  13. System.Classes,
  14. Vcl.Graphics,
  15. Vcl.Controls,
  16. Vcl.Forms,
  17. Vcl.Dialogs,
  18. Vcl.ComCtrls,
  19. Vcl.StdCtrls,
  20. Vcl.ExtCtrls,
  21. QPlugins,
  22. QPlugins_loader_lib,
  23. QPlugins_Vcl_Messages;
  24.  
  25. type
  26. TForm1 = class(TForm)
  27. Panel1: TPanel;
  28. Button1: TButton;
  29. PageControl1: TPageControl;
  30. procedure FormCreate(Sender: TObject);
  31. procedure Button1Click(Sender: TObject);
  32. procedure PageControl1Resize(Sender: TObject);
  33. private
  34. { Private declarations }
  35. public
  36. { Public declarations }
  37. end;
  38.  
  39. // DLL中的接口,方法都由DLL的子类来实现
  40. IDockableControl = interface
  41. ['{D0A4BDFA-CB29-4725-9158-C199B9C373C9}']
  42. procedure DockTo(AHandle: HWND); stdcall;
  43. procedure HostSizeChanged; stdcall;
  44. end;
  45.  
  46. // 加强的Tabsheet
  47. TDockHostPage = class(TTabSheet)
  48. private
  49. procedure SetDockedControl(const Value: IDockableControl);
  50. protected
  51. FDockedControl: IDockableControl;
  52. public
  53. property DockedControl: IDockableControl read FDockedControl write SetDockedControl;
  54. end;
  55.  
  56. var
  57. Form1: TForm1;
  58.  
  59. implementation
  60.  
  61. {$R *.dfm}
  62.  
  63. // 按钮_新页
  64. procedure TForm1.Button1Click(Sender: TObject);
  65. var
  66. ACtrl: IDockableControl;
  67. ATabSheet: TDockHostPage;
  68. begin
  69. // 根据'Services/Docks/Frame'找到DLL中的TDockInstanceService服务
  70. ACtrl := PluginsManager.ByPath('Services/Docks/Frame') as IDockableControl;
  71. // 如果这个服务存在
  72. if Assigned(ACtrl) then
  73. begin
  74. // 创建一个加强的Tabsheet,并把DLL中的TDockInstanceService服务内嵌进去
  75. ATabSheet := TDockHostPage.Create(PageControl1);
  76. ATabSheet.PageControl := PageControl1;
  77. ATabSheet.Caption := '第 ' + IntToStr(PageControl1.PageCount) + ' 页';
  78. ATabSheet.DockedControl := ACtrl;
  79. // 激活
  80. PageControl1.ActivePage := ATabSheet;
  81. end
  82. else
  83. begin
  84. Application.MessageBox('Services/Docks/Frame 服务未注册,请编译DLL先。', '服务未注册', MB_OK or MB_ICONSTOP);
  85. end;
  86. end;
  87.  
  88. // 创建
  89. procedure TForm1.FormCreate(Sender: TObject);
  90. var
  91. APath: string;
  92. begin
  93. ReportMemoryLeaksOnShutdown := True;
  94. APath := ExtractFilePath(Application.ExeName);
  95. // 注册默认的 DLL 加载器,扩展名可以根据实际的情况随意修改,多个扩展名之间用逗号或分号分隔
  96. PluginsManager.Loaders.Add(TQDLLLoader.Create(APath, '.dll'));
  97. // 启动插件注册,如果要显示加载进度,可以注册IQNotify响应函数响应进度通知
  98. PluginsManager.Start;
  99. end;
  100.  
  101. // 窗口大小调整
  102. procedure TForm1.PageControl1Resize(Sender: TObject);
  103. var
  104. I: Integer;
  105. APage: TDockHostPage;
  106. begin
  107. // 遍历窗体
  108. for I := to PageControl1.PageCount - do
  109. begin
  110. APage := PageControl1.Pages[I] as TDockHostPage;
  111. if APage.DockedControl <> nil then
  112. begin
  113. APage.DockedControl.HostSizeChanged;
  114. end;
  115. end;
  116. end;
  117.  
  118. { TDockHostPage }
  119.  
  120. // 接口作为参数传过来就内嵌到加强的Tabsheet中
  121. procedure TDockHostPage.SetDockedControl(const Value: IDockableControl);
  122. begin
  123. if FDockedControl <> Value then
  124. begin
  125. FDockedControl := Value;
  126. if Assigned(Value) then
  127. begin
  128. // DLl中的内嵌窗口函数
  129. Value.DockTo(Handle);
  130. end;
  131. end;
  132. end;
  133.  
  134. 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. 关于ubuntu挂载ntfs无法进行读写的解决方法

    查看挂载信息 df -h 参看要挂载磁盘UUID sudo blkid 编辑/etc/fstab文件: sudo vim /etc/fstab 在最后一行添加如下一行信息: UUID=A248CF46 ...

  2. MySQL之约束

    目录 约束(CONSTRAINT) mysql中的约束有哪些? 级联操作 产生的原因: 两种级联的定义方式 约束(CONSTRAINT) 什么是约束? ​ 是一种限制,对某一个东西的限制.例如宪法规定 ...

  3. WPS 2019文档编辑 技巧

    wps2019文档怎么设置粘贴时自动匹配当前的格式: 菜单栏 文件 -- 选项 -- 编辑 -- 默认粘贴方式 设置为 匹配当前格式. 在编辑文档左侧或右侧显示/隐藏 目录/书签: 视图 -- 导航窗 ...

  4. SpringBoot Controller找不到视图路径

    在启动类加注解@ComponentScan("com.controller")即可,括号里表示Controller所在包名. 参考:https://blog.csdn.net/ji ...

  5. warning no match for this type name: entity.User [Xlint:invalidAbsoluteTypeName]

    这个bug是由于在spring的配置文件中的错误 这是由于上述中的 这一句中的这里的类名的引用错了,我的正确类名引用是 所以只要将包引用的包名修改为User类的完全限定名就可以了

  6. Java 实现简单的人机猜拳游戏

    import java.util.Scanner; import java.util.Random; public class TestGuess{ public static void main(S ...

  7. VMware安装CentOS操作系统详细步骤

    目录 创建虚拟机(买电脑) 1. 创建新虚拟机 2. 自定义配置虚拟机 3. 选择虚拟机硬件兼容性 4. 安装虚拟机创建系统 5. 选择虚拟机操作系统 6. 设置虚拟机名字和存放位置 7. 设置虚拟机 ...

  8. 【转载】如何快速转载CSDN中的博客

    前言   对于喜欢逛CSDN的人来说,看别人的博客确实能够对自己有不小的提高,有时候看到特别好的博客想转载下载,但是不能一个字一个字的敲了,这时候我们就想快速转载别人的博客,把别人的博客移到自己的空间 ...

  9. 新闻网大数据实时分析可视化系统项目——7、Kafka分布式集群部署

    Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cloudera.Apache Storm.Spa ...

  10. java虚拟机之内存分配

    Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配.同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收. JDK1.8之前的堆内存示意图: 从上图可以看出堆内存分为新 ...