zoukankan      html  css  js  c++  java
  • 004.Delphi插件之QPlugins,参数传递

    界面如下

    插件框架中大量使用了接口的东西,看的眼花缭乱,很多地方只做了申明,具体的实现是在另外的子类。

    DLL的代码如下

    unit ParamTest;
    
    interface
    
    uses
      classes,
      sysutils,
      types,
      QPlugins,
      qstring,
      qplugins_base,
      qplugins_params;
    
    type
      // 和主窗口一样的接口
      IList = interface
        ['{6D1A9CAB-9284-42DC-95C0-342DC72FAC03}']
        function Add(Item: Pointer): Integer;
        procedure Clear;
        procedure Delete(Index: Integer);
        procedure Exchange(Index1, Index2: Integer);
        function ExtractItem(Item: Pointer; Direction: TDirection): Pointer;
        function First: Pointer;
        function IndexOf(Item: Pointer): Integer;
        function IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
        procedure Insert(Index: Integer; Item: Pointer);
        function Last: Pointer;
        procedure Move(CurIndex, NewIndex: Integer);
        function Remove(Item: Pointer): Integer;
        function RemoveItem(Item: Pointer; Direction: TDirection): Integer;
        procedure Pack;
        procedure Sort(Compare: TListSortCompare);
        procedure SortList(const Compare: TListSortCompareFunc);
      end;
    
      // 和主窗口中一样的参数测试服务接口
      IParamTestService = interface
        ['{FB9443D9-EF9A-43F2-9F8D-9B838981AEBE}']
        procedure ObjectTest(AList: IList);
        procedure ArrayTest(AParams: IQParams);
        procedure StreamTest(AParams: IQParams);
        procedure StandTest(AParams: IQParams);
      end;
    
      // 参数测试服务接口,各函数的具体实现
      TParamTestService = class(TQService, IParamTestService)
      public
        procedure ObjectTest(AList: IList);
        procedure ArrayTest(AParams: IQParams);
        procedure StreamTest(AParams: IQParams);
        procedure StandTest(AParams: IQParams);
      end;
    
      // Log接口,
      ILogService = interface
        ['{C45581C0-C290-4A9A-BF9E-AC2D814593FE}']
        procedure Log(S: PWideChar);
      end;
    
    implementation
    
    { TParamTestService }
    
    // 数组参数测试
    procedure TParamTestService.ArrayTest(AParams: IQParams);
    var
      ALog: ILogService;
      // 主界面传过来的参数
      procedure LogParams(AParent: IQParams);
      var
        I: Integer;
        AParam: IQParam;
        S: QStringW;
      begin
        S := '参数共 ' + IntToStr(AParent.Count) + '';
        ALog.Log(PWideChar(S));
        // 判断主界面传过来的参数,有多少个成员
        for I := 0 to AParent.Count - 1 do
        begin
          AParam := AParent[I];
          // 取出每次循环的名字和类型
          S := AParam.Name;
          // 判断参数类型
          if AParam.ParamType = ptArray then
          begin
            S := S + ' 是一个数组,遍历其元素:';
            ALog.Log(PWideChar(S));
            LogParams(AParam.AsArray);
            S := '子参数枚举结束';
            ALog.Log(PWideChar(S));
          end
          else
            ALog.Log(PWideChar(S + ' 的值为:' + AParam.AsString.Value));
        end;
      end;
    
    begin
      ALog := PluginsManager as ILogService;
      // 神奇!插件中ALog是没有实体的,实体部分是在主程序实现,在插件中的函数调用的也是主程序中的方法
      LogParams(AParams);
    end;
    
    // 对象参数测试
    procedure TParamTestService.ObjectTest(AList: IList);
    var
      I: Integer;
    begin
      // 从主程序传入一个空的AList,在插件中处理这个AList
      for I := 0 to 9 do
      begin
        AList.Add(Pointer(I));
      end;
    end;
    
    // 标准参数测试
    procedure TParamTestService.StandTest(AParams: IQParams);
    var
      ALog: ILogService;
      // 主界面传过来的参数
      procedure LogParams(AParent: IQParams);
      var
        I: Integer;
        AParam: IQParam;
        S: QStringW;
      begin
        S := '参数共 ' + IntToStr(AParent.Count) + '';
        ALog.Log(PWideChar(S));
        // 判断主界面传过来的参数,有多少个成员
        for I := 0 to AParent.Count - 1 do
        begin
          AParam := AParent[I];
          // 取出每次循环的名字和类型
          S := AParam.Name;
          if AParam.ParamType = ptArray then
          begin
            S := S + ' 是一个数组,遍历其元素:';
            ALog.Log(PWideChar(S));
            LogParams(AParam.AsArray);
            S := '子参数枚举结束';
            ALog.Log(PWideChar(S));
          end
          else
          begin
            // 输出
            ALog.Log(PWideChar(S + ' 的值为:' + AParam.AsString.Value));
          end;
        end;
      end;
    
    begin
      // 输出函数是实体是在主窗口实现的
      ALog := PluginsManager as ILogService;
      // 神奇!插件中ALog是没有实体的,实体部分是在主程序实现,在插件中的函数调用的也是主程序中的方法
      ALog.Log('曾经沧海难为水!');
      LogParams(AParams);
    end;
    
    // 流参数测试
    procedure TParamTestService.StreamTest(AParams: IQParams);
    var
      AStream: TQStream;
      S: QStringW;
    begin
      // 读取插件流内容
      AStream := TQStream.Create(AParams[0].AsStream);
      try
        S := '这是从插件中返回的内容。';
        AStream.Size := 0;
        // 写入内容
        AStream.WriteBuffer(PWideChar(S)^, Length(S) shl 1);
      finally
        FreeObject(AStream);
      end;
    end;
    
    initialization
    
    // 单元初始化时,注册Params服务插件
    RegisterServices('Services', [TParamTestService.Create(IParamTestService, 'Params')]);
    
    finalization
    
    // 注销Params服务插件
    UnregisterServices('Services', ['Params']);
    
    end.

    EXE代码如下

    unit Frm_Main;
    
    
    interface
    
    uses
      Winapi.Windows,
      Winapi.Messages,
      System.SysUtils,
      Types,
      System.Variants,
      System.Classes,
      Vcl.Graphics,
      Vcl.Controls,
      Vcl.Forms,
      Vcl.Dialogs,
      qstring,
      QPlugins,
      Vcl.StdCtrls,
      Vcl.ExtCtrls,
      qplugins_base,
      qplugins_params,
      qplugins_loader_lib;
    
    type
      // 这个演示如何将对象进行封装,做为参数在服务间传递
      // IList接口,具体都是在子方法中实现
      IList = interface
        ['{6D1A9CAB-9284-42DC-95C0-342DC72FAC03}']
        function Add(Item: Pointer): Integer;
        procedure Clear;
        procedure Delete(Index: Integer);
        procedure Exchange(Index1, Index2: Integer);
        function ExtractItem(Item: Pointer; Direction: TDirection): Pointer;
        function First: Pointer;
        function IndexOf(Item: Pointer): Integer;
        function IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
        procedure Insert(Index: Integer; Item: Pointer);
        function Last: Pointer;
        procedure Move(CurIndex, NewIndex: Integer);
        function Remove(Item: Pointer): Integer;
        function RemoveItem(Item: Pointer; Direction: TDirection): Integer;
        procedure Pack;
        procedure Sort(Compare: TListSortCompare);
        procedure SortList(const Compare: TListSortCompareFunc);
        function GetCount: Integer;
        function GetItem(Index: Integer): Pointer;
      end;
    
      // 参数测试服务,对应的4个方法
      IParamTestService = interface
        ['{FB9443D9-EF9A-43F2-9F8D-9B838981AEBE}']
        procedure ObjectTest(AList: IList);
        procedure ArrayTest(AParams: IQParams);
        procedure StreamTest(AParams: IQParams);
        procedure StandTest(AParams: IQParams);
      end;
    
      // 对上面的接口进行封装,以便在服务间传递
      TListWrap = class(TQInterfacedObject, IList)
      protected
        FList: TList;
      public
        constructor Create; override;
        destructor Destroy; override;
        function Add(Item: Pointer): Integer;
        procedure Clear;
        procedure Delete(Index: Integer);
        procedure Exchange(Index1, Index2: Integer);
        function ExtractItem(Item: Pointer; Direction: TDirection): Pointer;
        function First: Pointer;
        function IndexOf(Item: Pointer): Integer;
        function IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
        procedure Insert(Index: Integer; Item: Pointer);
        function Last: Pointer;
        procedure Move(CurIndex, NewIndex: Integer);
        function Remove(Item: Pointer): Integer;
        function RemoveItem(Item: Pointer; Direction: TDirection): Integer;
        procedure Pack;
        procedure Sort(Compare: TListSortCompare);
        procedure SortList(const Compare: TListSortCompareFunc);
        function GetCount: Integer;
        function GetItem(Index: Integer): Pointer;
      end;
    
      // 输出接口,只定义,子类实现
      ILogService = interface
        ['{C45581C0-C290-4A9A-BF9E-AC2D814593FE}']
        procedure Log(S: PWideChar);
      end;
    
      TLogService = class(TQService, ILogService)
      public
        // 输出接口的实现
        procedure Log(S: PWideChar);
      end;
    
      TForm1 = class(TForm)
        Panel1: TPanel;
        Memo1: TMemo;
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
    
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    { TListWrap }
    
    function TListWrap.Add(Item: Pointer): Integer;
    begin
      Result := FList.Add(Item);
    end;
    
    procedure TListWrap.Clear;
    begin
      FList.Clear;
    end;
    
    constructor TListWrap.Create;
    begin
      inherited;
      FList := TList.Create;
    end;
    
    procedure TListWrap.Delete(Index: Integer);
    begin
      FList.Delete(Index);
    end;
    
    destructor TListWrap.Destroy;
    begin
      FreeAndNil(FList);
      inherited;
    end;
    
    procedure TListWrap.Exchange(Index1, Index2: Integer);
    begin
      FList.Exchange(Index1, Index2);
    end;
    
    function TListWrap.ExtractItem(Item: Pointer; Direction: TDirection): Pointer;
    begin
      Result := FList.ExtractItem(Item, Direction);
    end;
    
    function TListWrap.First: Pointer;
    begin
      Result := FList.First;
    end;
    
    function TListWrap.GetCount: Integer;
    begin
      Result := FList.Count;
    end;
    
    function TListWrap.GetItem(Index: Integer): Pointer;
    begin
      Result := FList[Index];
    end;
    
    function TListWrap.IndexOf(Item: Pointer): Integer;
    begin
      Result := FList.IndexOf(Item);
    end;
    
    function TListWrap.IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
    begin
      Result := FList.IndexOfItem(Item, Direction);
    end;
    
    procedure TListWrap.Insert(Index: Integer; Item: Pointer);
    begin
      FList.Insert(Index, Item);
    end;
    
    function TListWrap.Last: Pointer;
    begin
      Result := FList.Last;
    end;
    
    procedure TListWrap.Move(CurIndex, NewIndex: Integer);
    begin
      FList.Move(CurIndex, NewIndex);
    end;
    
    procedure TListWrap.Pack;
    begin
      FList.Pack;
    end;
    
    function TListWrap.Remove(Item: Pointer): Integer;
    begin
      Result := FList.Remove(Item);
    end;
    
    function TListWrap.RemoveItem(Item: Pointer; Direction: TDirection): Integer;
    begin
      Result := FList.RemoveItem(Item, Direction);
    end;
    
    procedure TListWrap.Sort(Compare: TListSortCompare);
    begin
      FList.Sort(Compare);
    end;
    
    procedure TListWrap.SortList(const Compare: TListSortCompareFunc);
    begin
      FList.SortList(Compare);
    end;
    
    // 按钮_对象作为参数
    procedure TForm1.Button1Click(Sender: TObject);
    var
      AList: IList;
      AService: IParamTestService;
      I: Integer;
    begin
      Memo1.Lines.Add('【通过接口传递对象演示】');
      // 定义一个接口,子类创建,拥有子类的各种属性
      AList := TListWrap.Create;
      // 通过路径获取指定的服务接口实例
      AService := PluginsManager.ByPath('Services/Params') as IParamTestService;
      // 如果插件对象存在
      if Assigned(AService) then
      begin
        // 从主程序传入一个空的AList,在插件中处理这个AList
        AService.ObjectTest(AList);
        for I := 0 to AList.GetCount - 1 do
        begin
          Memo1.Lines.Add(IntToStr(I) + ' - ' + IntToHex(IntPtr(AList.GetItem(I)), SizeOf(Pointer) shl 1));
        end;
      end;
    end;
    
    // 按钮_流做为参数
    procedure TForm1.Button2Click(Sender: TObject);
    var
      AParams: IQParams;
      AService: IParamTestService;
      AStream: TQStream;
      S: QStringW;
    begin
      Memo1.Lines.Add('【流做为参数传递演示】');
      // 创建参数类
      AParams := TQParams.Create;
      // 类型设置成流
      AStream := QStream(AParams.Add('Stream', ptStream).GetAsStream);
      S := 'Hello,world';
      AStream.WriteBuffer(PWideChar(S)^, Length(S) shl 1);
      // 通过路径获取指定的服务接口实例
      AService := PluginsManager.ByPath('Services/Params') as IParamTestService;
      // 如果插件对象存在
      if Assigned(AService) then
      begin
        // 调用插件中的StreamTest实例,执行之后AStream文本内容变成了插件反馈的内容
        AService.StreamTest(AParams);
        // 输出
        AStream.Position := 0;
        S := LoadTextW(AStream, teUnicode16LE);
        Memo1.Lines.Add(Format('新的流内容:"%s" ', [S]));
      end;
      FreeAndNil(AStream);
    end;
    
    // 按钮_二维参数
    procedure TForm1.Button3Click(Sender: TObject);
    var
      AParams, ASubParams: IQParams;
      AService: IParamTestService;
    begin
      Memo1.Lines.Add('【二维参数演示】');
      AParams := TQParams.Create;
      ASubParams := AParams.Add('Subs', ptArray).AsArray;
      ASubParams.Add('Name', ptUnicodeString).AsString := NewString('QDAC');
      ASubParams.Add('Version', ptUInt8).AsInteger := 3;
      Memo1.Lines.Add('原始参数');
      Memo1.Lines.Add(AParams.AsString.Value);
      // 通过路径获取指定的服务接口实例
      AService := PluginsManager.ByPath('Services/Params') as IParamTestService;
      // 如果插件对象存在
      if Assigned(AService) then
      begin
        // 调用插件中的ArrayTest实例
        AService.ArrayTest(AParams);
      end;
    end;
    
    // 按钮_普通参数
    procedure TForm1.Button4Click(Sender: TObject);
    var
      AParams: IQParams;
      AService: IParamTestService;
    begin
      Memo1.Lines.Add('【常规参数传递演示】');
      // 给参数添加2个不同类型的成员
      AParams := TQParams.Create;
      AParams.Add('Int', ptInt32).AsInteger := 100;
      AParams.Add('DT', ptDateTime).AsFloat := Now;
      // 通过路径获取指定的服务接口实例
      AService := PluginsManager.ByPath('Services/Params') as IParamTestService;
      // 如果插件对象存在
      if Assigned(AService) then
      begin
        // 调用插件中的StandTest实例
        AService.StandTest(AParams);
      end;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      ReportMemoryLeaksOnShutDown := True;
      // 注册Log日志接口,其实就是下面的一个输出函数
      RegisterServices('/Services', [TLogService.Create(ILogService, 'Log')]);
      // 加载同目录的DLL
      PluginsManager.Loaders.Add(TQDLLLoader.Create(ExtractFilePath(Application.ExeName), '.DLL'));
      // 启动所有的加载器加载支持的插件
      PluginsManager.Start;
    end;
    
    { TLogService }
    
    // 输出接口的实现
    procedure TLogService.Log(S: PWideChar);
    begin
      //具体实现,就是一个输出函数
      Form1.Memo1.Lines.Add(S);
    end;
    
    end.
  • 相关阅读:
    调用其他类函数,且其他类函数使用自己脚本的成员变量的方法
    伟程君解决端口被占用问题(接口jmeter 本地端口被占用完了,jmeter报错的问题)(亲测是可以的)
    JMeter 使用 http长连接的方法
    解决端口被占用问题(端口timewait)
    光辉岁月吉他指弹
    Jmeter获取 json字符的另外一种写法
    Jmeter-Critical Section Controller(临界区控制器)(还没看,是一个控制请求按顺序执行的东东)
    wrk一个能做模拟高并发请求的东东
    017-mac下project
    016-mac下ps
  • 原文地址:https://www.cnblogs.com/tianpan2019/p/11491877.html
Copyright © 2011-2022 走看看