I have a function that returns TArray<TValue> given a TArgList.
function GetParameters(Args: TArgList): TArray<TValue>;
var
Parameters: TArray<TValue>;
I: Integer;
function ArgParam(Index: Integer): OleVariant;
begin
Result := OleVariant(Args.Arguments[Args.Count - Index - 1]);
end;
begin
Parameters := nil;
for I := 0 to Args.Count - 1 do
begin
SetLength(Parameters, Length(Parameters) + 1);
Parameters[High(Parameters)] := TValue.FromVariant(ArgParam(I));
end;
Result := Parameters;
end;
The result of this function is then passed to invoke an RTTI Method.
procedure ExecMethod(MethodName: string; Args: TArray<TValue>);
var
Method: TRttiMethod;
Ctx: TRttiContext;
vType: TRttiType;
I: Integer;
begin
vType := nil;
Ctx := TRttiContext.Create;
try
vType := Ctx.GetType(FControl.ClassInfo);
for Method in vType.GetMethods do
begin
if SameText(Method.Name, MethodName) then
break;
end;
if Assigned(Method) then
Method.Invoke(FControl, Args);
finally
Ctx.Free;
vType.Free;
end;
end;
This works fine on simple types e.g. int, string or boolean etc. However, when one of the argument is an object/component. That's where I'm hitting a wall. Somehow, I need to convert or type cast an argument if the method expects object/component there.
Parameters[High(Parameters)] := TValue.FromVariant(ArgParam(Args, I));
How do I convert it to TValue ? Tried TValue.From<TObject>, TValue.From<Pointer> but I'm still getting invalid typecast or access violation.
Thanks for the replies.
Addendum
TArgList = record
Arguments: PVariantArgList;
Count: Integer;
end;
PVariantArgList is declared in ActiveX
The Invoke signature is :
function Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
var
DispParams: PDispParams;
**ArgList: TArgList;**
begin
DispParams := @Params;
ArgList.Count := DispParams.cArgs;
ArgList.Arguments := DispParams.rgvarg;
Result := DISP_E_BADINDEX;
try
if Flags and DISPATCH_METHOD = DISPATCH_METHOD then
begin
Dec(DispId, BaseMethodDispid);
if (DispId > -1) and (DispId < FMethods.Count) then
begin
Result := S_OK;
ExecMethod(FMethods[DispId], GetParameters(ArgList));
end
end
.
.
.
FMethods is simply a string list of methods. Where DispID is the index in that list of the method name.
TArgList
? – Stefan GlienkeSetLength()
inside the loop is overkill, you should call it one time before entering the loop. Also, your code does not account for method overloads. You can't go off of name alone, you should enumerate the methods until you find one whose parameter list matches the values being passed in. – Remy Lebeau