gpt4 book ai didi

delphi - RTTI TRttiMethod.Invoke、stdcall 和 const 参数的错误

转载 作者:行者123 更新时间:2023-12-03 14:58:03 29 4
gpt4 key购买 nike

我对 RTTI TRttiMethod.Invoke、stdcall 和 const 参数有疑问:

    obj := TClassRecordTest.Create;
try
b.a := 10; b.b := 100;

a.a := 1; a.b := 2;
writeln('b.a='+IntToStr(b.a)+' b.b='+IntToStr(b.b));
writeln;
writeln('call test1');
writeln('a.a='+IntToStr(a.a)+' a.b='+IntToStr(a.b));
r := VToRec(RTTICall(obj, 'Test1', @a, @b));
writeln('test1 r.a='+IntToStr(r.a)+' r.b='+IntToStr(r.b));

a.a := 2; a.b := 3;
writeln('call test2');
writeln('a.a='+IntToStr(a.a)+' a.b='+IntToStr(a.b));
r := VToRec(RTTICall(obj, 'Test2', @a, @b));
writeln('test3 r.a='+IntToStr(r.a)+' r.b='+IntToStr(r.b));

a.a := 3; a.b := 4;
writeln('call test3');
writeln('a.a='+IntToStr(a.a)+' a.b='+IntToStr(a.b));
r := VToRec(RTTICall(obj, 'Test3', @a, @b));
writeln('test3 r.a='+IntToStr(r.a)+' r.b='+IntToStr(r.b));

a.a := 4; a.b := 5;
writeln('call test4');
writeln('a.a='+IntToStr(a.a)+' a.b='+IntToStr(a.b));
r := VToRec(RTTICall(obj, 'Test4', @a, @b));
writeln('test4 r.a='+IntToStr(r.a)+' r.b='+IntToStr(r.b));

finally
obj.Destroy;
end;

RTTI调用它是:

function RTTICall(aObj: TObject; MethodName: string; a, b: pointer): TValue;
var
RttiContext: TRttiContext;
ClassType: TRttiType;
Methods: TMethodList;
Method: TRttiMethod;
Params: TParamList;
Args: TArgList;
begin
RttiContext := TRttiContext.Create;
try
ClassType := FindFirstClassTypeByName(RttiContext, aObj.ClassName);
if ClassType <> nil then
begin
Methods := ClassType.GetDeclaredMethods;
for Method in Methods
do begin
if SameText(Method.Name, MethodName) then
begin
Params := Method.GetParameters;
SetLength(Args, Length(Params));
TValue.Make(nil, Params[0].ParamType.Handle, Args[0]);
move(a^, Args[0].GetReferenceToRawData^, Params[0].ParamType.TypeSize);
TValue.Make(nil, Params[1].ParamType.Handle, Args[1]);
move(b^, Args[1].GetReferenceToRawData^, Params[1].ParamType.TypeSize);

Result := Method.Invoke(TObject(aObj), Args);
exit;
end;
end;
end;
finally
// FreeAndNil(aObj);
end;
end;

和函数 TestN:

function TClassRecordTest.Test1(a, b: TRecordTest): TRecordTest;
begin
result.a := a.a+b.a;
result.b := a.b+b.b;
end;

function TClassRecordTest.Test2(var a, b: TRecordTest): TRecordTest;
begin
result.a := a.a+b.a;
result.b := a.b+b.b;
end;

function TClassRecordTest.Test3(const a, b: TRecordTest): TRecordTest;
begin
result.a := a.a+b.a;
result.b := a.b+b.b;
end;

function TClassRecordTest.Test4(const a, b: TRecordTest): TRecordTest;
begin
result.a := a.a+b.a;
result.b := a.b+b.b;
end;

结果是:

>Project7.exe
b.a=10 b.b=100

call test1
a.a=1 a.b=2
test1 r.a=11 r.b=102
call test2
a.a=2 a.b=3
test3 r.a=12 r.b=103
call test3
a.a=3 a.b=4
test3 r.a=13 r.b=104
call test4
a.a=4 a.b=5
EAccessViolation: Access violation at address 0047A65A in module 'Project7.exe'. Read of address 00000004

仅当用作 const 和 stdcall 参数时才会出现此错误。

如果我更改 Test3 和 Test4:

function TClassRecordTest.Test3(const a, b: TRecordTest): TRecordTest;
begin
writeLn('@a='+IntToStr(integer(@a))+' @b='+IntToStr(integer(@a)));
result.a := a.a+b.a;
result.b := a.b+b.b;
end;

function TClassRecordTest.Test4(const a, b: TRecordTest): TRecordTest;
begin
writeLn('@a='+IntToStr(integer(@a))+' @b='+IntToStr(integer(@a)));
result.a := a.a+b.a;
result.b := a.b+b.b;
end;

结果是:

>Project7.exe
b.a=10 b.b=100

call test1
a.a=1 a.b=2
test1 r.a=11 r.b=102
call test2
a.a=2 a.b=3
test3 r.a=12 r.b=103
call test3
a.a=3 a.b=4
@a=31301448 @b=31301448
test3 r.a=13 r.b=104
call test4
a.a=4 a.b=5
@a=4 @b=4
EAccessViolation: Access violation at address 0047A76C in module 'Project7.exe'. Read of address 00000004

事实证明,TRttiMethod.Invoke const 按值传递,尽管需要传递地址

最佳答案

你也遇到了和我一样的问题。让我引用巴里的话:

This is by design; the Rtti.Invoke function is at too low a level on the stack, and has no access to any typeinfo that could tell it whether to pass arguments by reference or by value. It expects all parameters to be converted to the correct type, including any by-ref parameters being converted to pointers as needed. All it does is stuff the values into registers and/or stack as required, invoke, and retrieve the return value (if any) from the appropriate location.

因此,为了传递 const、out 和 var 参数,您需要使用 TValue.From ()

关于delphi - RTTI TRttiMethod.Invoke、stdcall 和 const 参数的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6421674/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com