zoukankan      html  css  js  c++  java
  • 012.Delphi插件之QPlugins,多实例内嵌窗口服务

    这个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(0, 0, 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 := 0 to PageControl1.PageCount - 1 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.
  • 相关阅读:
    字符串匹配算法的比较(BF算法/KMP算法/jdk自带的indexOf方法)
    重装Python(pip,anaconda,jupyter notebook)
    Python:词频统计及排序
    python压制警告
    StanfordCoreNLP的简单使用
    最常用的几个DOS命令
    (用大白话讲)为什么我们需要配置环境变量
    通配符 vs 正则表达式
    大白话<组件、控件、插件>三者的区别
    R语言:集合运算
  • 原文地址:https://www.cnblogs.com/tianpan2019/p/11498642.html
Copyright © 2011-2022 走看看