zoukankan      html  css  js  c++  java
  • 007.Delphi插件之QPlugins,插件的卸载和重新加载

    效果图如下,可以反复卸载和重新加载。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 := 0;
        end;
      end;
    
    begin
      // 取服务模块
      AModule := ServiceModule;
      // 如果模块存在
      if AModule <> 0 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.
  • 相关阅读:
    ntp时间服务器
    locate 命令
    身份验证器
    centos 6 mysql源码安装
    简单上传下载命令lrzsz
    iptables记录日志
    iptables日志探秘
    du 命令
    Codeforces 1097F Alex and a TV Show (莫比乌斯反演)
    线段树教做人系列(1)HDU4967 Handling the Past
  • 原文地址:https://www.cnblogs.com/tianpan2019/p/11495684.html
Copyright © 2011-2022 走看看