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.

 

posted @ 2019-09-09 15:17  像一棵海草海草海草  阅读(339)  评论(0编辑  收藏  举报