界面如下
插件框架中大量使用了接口的东西,看的眼花缭乱,很多地方只做了申明,具体的实现是在另外的子类。
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.