004.Delphi插件之QPlugins,参数传递

时间:2023-03-10 04:52:23
004.Delphi插件之QPlugins,参数传递

界面如下

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 := to AParent.Count - 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 := to 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 := to AParent.Count - 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[].AsStream);
try
S := '这是从插件中返回的内容。';
AStream.Size := ;
// 写入内容
AStream.WriteBuffer(PWideChar(S)^, Length(S) shl );
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 := to AList.GetCount - do
begin
Memo1.Lines.Add(IntToStr(I) + ' - ' + IntToHex(IntPtr(AList.GetItem(I)), SizeOf(Pointer) shl ));
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 );
// 通过路径获取指定的服务接口实例
AService := PluginsManager.ByPath('Services/Params') as IParamTestService;
// 如果插件对象存在
if Assigned(AService) then
begin
// 调用插件中的StreamTest实例,执行之后AStream文本内容变成了插件反馈的内容
AService.StreamTest(AParams);
// 输出
AStream.Position := ;
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 := ;
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 := ;
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.