delphi – 带有RTTI TRttiMethod.Invoke,stdcall和const参数的Bu
我有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',@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',@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',@b)); writeln('test4 r.a='+IntToStr(r.a)+' r.b='+IntToStr(r.b)); finally obj.Destroy; end; RTTICall它是: 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按值传递,尽管有必要传递地址 解决方法
你和我一样遇到了同样的问题.让我引用巴里所说的话:
所以为了传递const,out和var参数,你需要使用TValue.From< Pointer>() (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |