mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-17 05:19:17 +02:00
+ add TRttiMethodType for method variables and TRttiProcedureType for procedure variables
git-svn-id: trunk@39888 -
This commit is contained in:
parent
b8ae04140c
commit
7bb147dce0
@ -294,6 +294,37 @@ type
|
|||||||
function ToString: String; override;
|
function ToString: String; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TRttiInvokableType = class(TRttiType)
|
||||||
|
protected
|
||||||
|
function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; virtual; abstract;
|
||||||
|
function GetCallingConvention: TCallConv; virtual; abstract;
|
||||||
|
function GetReturnType: TRttiType; virtual; abstract;
|
||||||
|
public
|
||||||
|
function GetParameters: specialize TArray<TRttiParameter>; inline;
|
||||||
|
property CallingConvention: TCallConv read GetCallingConvention;
|
||||||
|
property ReturnType: TRttiType read GetReturnType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TRttiMethodType = class(TRttiInvokableType)
|
||||||
|
private
|
||||||
|
FCallConv: TCallConv;
|
||||||
|
FReturnType: TRttiType;
|
||||||
|
FParams, FParamsAll: specialize TArray<TRttiParameter>;
|
||||||
|
protected
|
||||||
|
function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; override;
|
||||||
|
function GetCallingConvention: TCallConv; override;
|
||||||
|
function GetReturnType: TRttiType; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TRttiProcedureType = class(TRttiInvokableType)
|
||||||
|
private
|
||||||
|
FParams, FParamsAll: specialize TArray<TRttiParameter>;
|
||||||
|
protected
|
||||||
|
function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; override;
|
||||||
|
function GetCallingConvention: TCallConv; override;
|
||||||
|
function GetReturnType: TRttiType; override;
|
||||||
|
end;
|
||||||
|
|
||||||
TDispatchKind = (
|
TDispatchKind = (
|
||||||
dkStatic,
|
dkStatic,
|
||||||
dkVtable,
|
dkVtable,
|
||||||
@ -555,6 +586,21 @@ type
|
|||||||
constructor Create(AVmtMethodParam: PVmtMethodParam);
|
constructor Create(AVmtMethodParam: PVmtMethodParam);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TRttiMethodTypeParameter = class(TRttiParameter)
|
||||||
|
private
|
||||||
|
fHandle: Pointer;
|
||||||
|
fName: String;
|
||||||
|
fFlags: TParamFlags;
|
||||||
|
fType: PTypeInfo;
|
||||||
|
protected
|
||||||
|
function GetHandle: Pointer; override;
|
||||||
|
function GetName: String; override;
|
||||||
|
function GetFlags: TParamFlags; override;
|
||||||
|
function GetParamType: TRttiType; override;
|
||||||
|
public
|
||||||
|
constructor Create(aHandle: Pointer; const aName: String; aFlags: TParamFlags; aType: PTypeInfo);
|
||||||
|
end;
|
||||||
|
|
||||||
TRttiIntfMethod = class(TRttiMethod)
|
TRttiIntfMethod = class(TRttiMethod)
|
||||||
private
|
private
|
||||||
FIntfMethodEntry: PIntfMethodEntry;
|
FIntfMethodEntry: PIntfMethodEntry;
|
||||||
@ -875,6 +921,8 @@ begin
|
|||||||
tkWString : Result := TRttiStringType.Create(ATypeInfo);
|
tkWString : Result := TRttiStringType.Create(ATypeInfo);
|
||||||
tkFloat : Result := TRttiFloatType.Create(ATypeInfo);
|
tkFloat : Result := TRttiFloatType.Create(ATypeInfo);
|
||||||
tkPointer : Result := TRttiPointerType.Create(ATypeInfo);
|
tkPointer : Result := TRttiPointerType.Create(ATypeInfo);
|
||||||
|
tkProcVar : Result := TRttiProcedureType.Create(ATypeInfo);
|
||||||
|
tkMethod : Result := TRttiMethodType.Create(ATypeInfo);
|
||||||
else
|
else
|
||||||
Result := TRttiType.Create(ATypeInfo);
|
Result := TRttiType.Create(ATypeInfo);
|
||||||
end;
|
end;
|
||||||
@ -1212,6 +1260,43 @@ begin
|
|||||||
FVmtMethodParam := AVmtMethodParam;
|
FVmtMethodParam := AVmtMethodParam;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TRttiMethodTypeParameter }
|
||||||
|
|
||||||
|
function TRttiMethodTypeParameter.GetHandle: Pointer;
|
||||||
|
begin
|
||||||
|
Result := fHandle;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiMethodTypeParameter.GetName: String;
|
||||||
|
begin
|
||||||
|
Result := fName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiMethodTypeParameter.GetFlags: TParamFlags;
|
||||||
|
begin
|
||||||
|
Result := fFlags;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiMethodTypeParameter.GetParamType: TRttiType;
|
||||||
|
var
|
||||||
|
context: TRttiContext;
|
||||||
|
begin
|
||||||
|
context := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
Result := context.GetType(FType);
|
||||||
|
finally
|
||||||
|
context.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TRttiMethodTypeParameter.Create(aHandle: Pointer; const aName: String; aFlags: TParamFlags; aType: PTypeInfo);
|
||||||
|
begin
|
||||||
|
fHandle := aHandle;
|
||||||
|
fName := aName;
|
||||||
|
fFlags := aFlags;
|
||||||
|
fType := aType;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TRttiIntfMethod }
|
{ TRttiIntfMethod }
|
||||||
|
|
||||||
function TRttiIntfMethod.GetHandle: Pointer;
|
function TRttiIntfMethod.GetHandle: Pointer;
|
||||||
@ -2235,6 +2320,199 @@ begin
|
|||||||
Result := GetParameters(False);
|
Result := GetParameters(False);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TRttiInvokableType }
|
||||||
|
|
||||||
|
function TRttiInvokableType.GetParameters: specialize TArray<TRttiParameter>;
|
||||||
|
begin
|
||||||
|
Result := GetParameters(False);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiMethodType }
|
||||||
|
|
||||||
|
function TRttiMethodType.GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>;
|
||||||
|
type
|
||||||
|
TParamInfo = record
|
||||||
|
Handle: Pointer;
|
||||||
|
Flags: TParamFlags;
|
||||||
|
Name: String;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PParamFlags = ^TParamFlags;
|
||||||
|
PCallConv = ^TCallConv;
|
||||||
|
PPPTypeInfo = ^PPTypeInfo;
|
||||||
|
|
||||||
|
var
|
||||||
|
infos: array of TParamInfo;
|
||||||
|
total, visible, i: SizeInt;
|
||||||
|
ptr: PByte;
|
||||||
|
paramtypes: PPPTypeInfo;
|
||||||
|
context: TRttiContext;
|
||||||
|
obj: TRttiObject;
|
||||||
|
begin
|
||||||
|
if aWithHidden and (Length(FParamsAll) > 0) then
|
||||||
|
Exit(FParamsAll);
|
||||||
|
if not aWithHidden and (Length(FParams) > 0) then
|
||||||
|
Exit(FParams);
|
||||||
|
|
||||||
|
ptr := @FTypeData^.ParamList[0];
|
||||||
|
visible := 0;
|
||||||
|
total := 0;
|
||||||
|
|
||||||
|
if FTypeData^.ParamCount > 0 then begin
|
||||||
|
SetLength(infos, FTypeData^.ParamCount);
|
||||||
|
|
||||||
|
while total < FTypeData^.ParamCount do begin
|
||||||
|
infos[total].Handle := ptr;
|
||||||
|
infos[total].Flags := PParamFlags(ptr)^;
|
||||||
|
Inc(ptr, SizeOf(TParamFlags));
|
||||||
|
{ handle name }
|
||||||
|
infos[total].Name := PShortString(ptr)^;
|
||||||
|
Inc(ptr, ptr^ + SizeOf(Byte));
|
||||||
|
{ skip type name }
|
||||||
|
Inc(ptr, ptr^ + SizeOf(Byte));
|
||||||
|
{ align? }
|
||||||
|
if not (pfHidden in infos[total].Flags) then
|
||||||
|
Inc(visible);
|
||||||
|
Inc(total);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if FTypeData^.MethodKind in [mkFunction, mkClassFunction] then begin
|
||||||
|
{ skip return type name }
|
||||||
|
ptr := AlignTypeData(PByte(ptr) + ptr^ + SizeOf(Byte));
|
||||||
|
{ handle return type }
|
||||||
|
FReturnType := GRttiPool.GetType(PPPTypeInfo(ptr)^^);
|
||||||
|
Inc(ptr, SizeOf(PPTypeInfo));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ handle calling convention }
|
||||||
|
FCallConv := PCallConv(ptr)^;
|
||||||
|
Inc(ptr, SizeOf(TCallConv));
|
||||||
|
|
||||||
|
SetLength(FParamsAll, FTypeData^.ParamCount);
|
||||||
|
SetLength(FParams, visible);
|
||||||
|
|
||||||
|
if FTypeData^.ParamCount > 0 then begin
|
||||||
|
context := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
paramtypes := PPPTypeInfo(ptr);
|
||||||
|
visible := 0;
|
||||||
|
for i := 0 to FTypeData^.ParamCount - 1 do begin
|
||||||
|
obj := context.GetByHandle(infos[i].Handle);
|
||||||
|
if Assigned(obj) then
|
||||||
|
FParamsAll[i] := obj as TRttiMethodTypeParameter
|
||||||
|
else begin
|
||||||
|
FParamsAll[i] := TRttiMethodTypeParameter.Create(infos[i].Handle, infos[i].Name, infos[i].Flags, paramtypes[i]^);
|
||||||
|
context.AddObject(FParamsAll[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not (pfHidden in infos[i].Flags) then begin
|
||||||
|
FParams[visible] := FParamsAll[i];
|
||||||
|
Inc(visible);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
context.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if aWithHidden then
|
||||||
|
Result := FParamsAll
|
||||||
|
else
|
||||||
|
Result := FParams;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiMethodType.GetCallingConvention: TCallConv;
|
||||||
|
begin
|
||||||
|
{ the calling convention is located after the parameters, so get the parameters
|
||||||
|
which will also initialize the calling convention }
|
||||||
|
GetParameters(True);
|
||||||
|
Result := FCallConv;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiMethodType.GetReturnType: TRttiType;
|
||||||
|
begin
|
||||||
|
if FTypeData^.MethodKind in [mkFunction, mkClassFunction] then begin
|
||||||
|
{ the return type is located after the parameters, so get the parameters
|
||||||
|
which will also initialize the return type }
|
||||||
|
GetParameters(True);
|
||||||
|
Result := FReturnType;
|
||||||
|
end else
|
||||||
|
Result := Nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiProcedureType }
|
||||||
|
|
||||||
|
function TRttiProcedureType.GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>;
|
||||||
|
var
|
||||||
|
visible, i: SizeInt;
|
||||||
|
param: PProcedureParam;
|
||||||
|
obj: TRttiObject;
|
||||||
|
context: TRttiContext;
|
||||||
|
begin
|
||||||
|
if aWithHidden and (Length(FParamsAll) > 0) then
|
||||||
|
Exit(FParamsAll);
|
||||||
|
if not aWithHidden and (Length(FParams) > 0) then
|
||||||
|
Exit(FParams);
|
||||||
|
|
||||||
|
if FTypeData^.ProcSig.ParamCount = 0 then
|
||||||
|
Exit(Nil);
|
||||||
|
|
||||||
|
SetLength(FParamsAll, FTypeData^.ProcSig.ParamCount);
|
||||||
|
SetLength(FParams, FTypeData^.ProcSig.ParamCount);
|
||||||
|
|
||||||
|
context := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
param := AlignTypeData(PProcedureParam(@FTypeData^.ProcSig.ParamCount + SizeOf(FTypeData^.ProcSig.ParamCount)));
|
||||||
|
visible := 0;
|
||||||
|
for i := 0 to FTypeData^.ProcSig.ParamCount - 1 do begin
|
||||||
|
obj := context.GetByHandle(param);
|
||||||
|
if Assigned(obj) then
|
||||||
|
FParamsAll[i] := obj as TRttiMethodTypeParameter
|
||||||
|
else begin
|
||||||
|
FParamsAll[i] := TRttiMethodTypeParameter.Create(param, param^.Name, param^.ParamFlags, param^.ParamType);
|
||||||
|
context.AddObject(FParamsAll[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not (pfHidden in param^.ParamFlags) then begin
|
||||||
|
FParams[visible] := FParamsAll[i];
|
||||||
|
Inc(visible);
|
||||||
|
end;
|
||||||
|
|
||||||
|
param := PProcedureParam(AlignTypeData(PByte(@param^.Name) + Length(param^.Name) + SizeOf(param^.Name[0])));
|
||||||
|
end;
|
||||||
|
|
||||||
|
SetLength(FParams, visible);
|
||||||
|
finally
|
||||||
|
context.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if aWithHidden then
|
||||||
|
Result := FParamsAll
|
||||||
|
else
|
||||||
|
Result := FParams;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProcedureType.GetCallingConvention: TCallConv;
|
||||||
|
begin
|
||||||
|
Result := FTypeData^.ProcSig.CC;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProcedureType.GetReturnType: TRttiType;
|
||||||
|
var
|
||||||
|
context: TRttiContext;
|
||||||
|
begin
|
||||||
|
if not Assigned(FTypeData^.ProcSig.ResultTypeRef) then
|
||||||
|
Exit(Nil);
|
||||||
|
|
||||||
|
context := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
Result := context.GetType(FTypeData^.ProcSig.ResultTypeRef^);
|
||||||
|
finally
|
||||||
|
context.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TRttiStringType }
|
{ TRttiStringType }
|
||||||
|
|
||||||
function TRttiStringType.GetStringKind: TRttiStringKind;
|
function TRttiStringType.GetStringKind: TRttiStringKind;
|
||||||
|
@ -70,6 +70,9 @@ type
|
|||||||
{$ifdef fpc}
|
{$ifdef fpc}
|
||||||
procedure TestInterfaceRaw;
|
procedure TestInterfaceRaw;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
procedure TestProcVar;
|
||||||
|
procedure TestMethod;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -155,7 +158,11 @@ type
|
|||||||
TTestSet = set of TTestEnum;
|
TTestSet = set of TTestEnum;
|
||||||
|
|
||||||
TTestProc = procedure;
|
TTestProc = procedure;
|
||||||
|
TTestFunc1 = function: LongInt;
|
||||||
|
TTestFunc2 = function(aArg1: LongInt; aArg2: array of LongInt): String;
|
||||||
TTestMethod = procedure of object;
|
TTestMethod = procedure of object;
|
||||||
|
TTestMethod1 = function: LongInt of object;
|
||||||
|
TTestMethod2 = function(aArg1: LongInt; aArg2: array of LongInt): String of object;
|
||||||
TTestHelper = class helper for TObject
|
TTestHelper = class helper for TObject
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1548,6 +1555,111 @@ begin
|
|||||||
context.Free;
|
context.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestProcVar;
|
||||||
|
var
|
||||||
|
context: TRttiContext;
|
||||||
|
t: TRttiType;
|
||||||
|
p: TRttiProcedureType;
|
||||||
|
params: {$ifdef fpc}specialize{$endif} TArray<TRttiParameter>;
|
||||||
|
begin
|
||||||
|
context := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
t := context.GetType(PTypeInfo(TypeInfo(TTestProc)));
|
||||||
|
Check(Assigned(t), 'Rtti Type is Nil');
|
||||||
|
Check(t is TRttiInvokableType, 'Rtti Type is not an invokeable');
|
||||||
|
Check(t is TRttiProcedureType, 'Rtti Type is not a procedure type');
|
||||||
|
|
||||||
|
p := t as TRttiProcedureType;
|
||||||
|
Check(p.CallingConvention = ccReg, 'Calling convention does not match');
|
||||||
|
Check(not Assigned(p.ReturnType), 'Return type is assigned');
|
||||||
|
CheckEquals(0, Length(p.GetParameters), 'Procedure variable has parameters');
|
||||||
|
|
||||||
|
t := context.GetType(PTypeInfo(TypeInfo(TTestFunc1)));
|
||||||
|
Check(Assigned(t), 'Rtti Type is Nil');
|
||||||
|
Check(t is TRttiInvokableType, 'Rtti Type is not an invokeable');
|
||||||
|
Check(t is TRttiProcedureType, 'Rtti Type is not a procedure type');
|
||||||
|
|
||||||
|
p := t as TRttiProcedureType;
|
||||||
|
Check(p.CallingConvention = ccReg, 'Calling convention does not match');
|
||||||
|
Check(Assigned(p.ReturnType), 'Return type is not assigned');
|
||||||
|
//Check(p.ReturnType is TRttiOrdinalType, 'Return type is not an ordinal type');
|
||||||
|
CheckEquals(0, Length(p.GetParameters), 'Procedure variable has parameters');
|
||||||
|
|
||||||
|
t := context.GetType(PTypeInfo(TypeInfo(TTestFunc2)));
|
||||||
|
Check(Assigned(t), 'Rtti Type is Nil');
|
||||||
|
Check(t is TRttiInvokableType, 'Rtti Type is not an invokeable');
|
||||||
|
Check(t is TRttiProcedureType, 'Rtti Type is not a procedure type');
|
||||||
|
|
||||||
|
p := t as TRttiProcedureType;
|
||||||
|
Check(p.CallingConvention = ccReg, 'Calling convention does not match');
|
||||||
|
Check(Assigned(p.ReturnType), 'Return type is not assigned');
|
||||||
|
Check(p.ReturnType is TRttiStringType, 'Return type is not a string type');
|
||||||
|
|
||||||
|
params := p.GetParameters;
|
||||||
|
CheckEquals(2, Length(params), 'Procedure variable has incorrect amount of parameters');
|
||||||
|
|
||||||
|
Check(params[0].ParamType.TypeKind in [tkInteger, tkInt64], 'Parameter 1 is not an ordinal type');
|
||||||
|
//Check(params[0].ParamType is TRttiOrdinalType, 'Parameter 1 is not an ordinal type');
|
||||||
|
Check(pfArray in params[1].Flags, 'Parameter 2 is not an array');
|
||||||
|
Check(params[1].ParamType.TypeKind in [tkInteger, tkInt64], 'Parameter 2 is not an ordinal array');
|
||||||
|
finally
|
||||||
|
context.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestMethod;
|
||||||
|
var
|
||||||
|
context: TRttiContext;
|
||||||
|
t: TRttiType;
|
||||||
|
m: TRttiMethodType;
|
||||||
|
params: {$ifdef fpc}specialize{$endif} TArray<TRttiParameter>;
|
||||||
|
begin
|
||||||
|
context := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
t := context.GetType(PTypeInfo(TypeInfo(TTestMethod)));
|
||||||
|
Check(Assigned(t), 'Rtti Type is Nil');
|
||||||
|
Check(t is TRttiInvokableType, 'Rtti Type is not an invokeable');
|
||||||
|
Check(t is TRttiMethodType, 'Rtti Type is not a method type');
|
||||||
|
|
||||||
|
m := t as TRttiMethodType;
|
||||||
|
Check(m.CallingConvention = ccReg, 'Calling convention does not match');
|
||||||
|
Check(not Assigned(m.ReturnType), 'Return type is assigned');
|
||||||
|
CheckEquals(0, Length(m.GetParameters), 'Method variable has parameters');
|
||||||
|
|
||||||
|
t := context.GetType(PTypeInfo(TypeInfo(TTestMethod1)));
|
||||||
|
Check(Assigned(t), 'Rtti Type is Nil');
|
||||||
|
Check(t is TRttiInvokableType, 'Rtti Type is not an invokeable');
|
||||||
|
Check(t is TRttiMethodType, 'Rtti Type is not a method type');
|
||||||
|
|
||||||
|
m := t as TRttiMethodType;
|
||||||
|
Check(m.CallingConvention = ccReg, 'Calling convention does not match');
|
||||||
|
Check(Assigned(m.ReturnType), 'Return type is not assigned');
|
||||||
|
//Check(p.ReturnType is TRttiOrdinalType, 'Return type is not an ordinal type');
|
||||||
|
CheckEquals(0, Length(m.GetParameters), 'Method variable has parameters');
|
||||||
|
|
||||||
|
t := context.GetType(PTypeInfo(TypeInfo(TTestMethod2)));
|
||||||
|
Check(Assigned(t), 'Rtti Type is Nil');
|
||||||
|
Check(t is TRttiInvokableType, 'Rtti Type is not an invokeable');
|
||||||
|
Check(t is TRttiMethodType, 'Rtti Type is not a method type');
|
||||||
|
|
||||||
|
m := t as TRttiMethodType;
|
||||||
|
Check(m.CallingConvention = ccReg, 'Calling convention does not match');
|
||||||
|
Check(Assigned(m.ReturnType), 'Return type is not assigned');
|
||||||
|
Check(m.ReturnType is TRttiStringType, 'Return type is not a string type');
|
||||||
|
|
||||||
|
params := m.GetParameters;
|
||||||
|
CheckEquals(2, Length(params), 'Method variable has incorrect amount of parameters');
|
||||||
|
|
||||||
|
Check(params[0].ParamType.TypeKind in [tkInteger, tkInt64], 'Parameter 1 is not an ordinal type');
|
||||||
|
//Check(params[0].ParamType is TRttiOrdinalType, 'Parameter 1 is not an ordinal type');
|
||||||
|
Check(pfArray in params[1].Flags, 'Parameter 2 is not an array');
|
||||||
|
Check(params[1].ParamType.TypeKind in [tkInteger, tkInt64], 'Parameter 2 is not an ordinal array');
|
||||||
|
finally
|
||||||
|
context.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
Loading…
Reference in New Issue
Block a user