Andre1 0 Posted Saturday at 02:49 PM Hi, this is a simplified example. I need to do generic calling. In procedure Main, while calling the Move command, an access violation is triggered. Why is the ByteArray not sucessfully filled? program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Rtti; type TMidiInputEvent = packed record Timestamp: Integer; Status: Byte; Data1: Byte; Data2: Byte; end; TMyObject = class public procedure TargetMethod(p: PPointer; len: PInteger); procedure CallMethodByName(const AMethodName: string; p: PPointer; len: PInteger); end; procedure TMyObject.TargetMethod(p: PPointer; len: PInteger); var EventCount: Integer; Events: TArray<TMidiInputEvent>; TotalSize: NativeUInt; I: Integer; begin SetLength(Events, 5); // 5 sample events for I := 0 to High(Events) do begin Events[I].Timestamp := 1000 + I * 100; Events[I].Status := $90; // Note On Events[I].Data1 := 60 + I; // MIDI note number Events[I].Data2 := 100; // Velocity end; EventCount := 5; TotalSize := EventCount * SizeOf(TMidiInputEvent); GetMem(p^, TotalSize); Move(Events[0], p^, TotalSize); len^ := TotalSize; end; procedure TMyObject.CallMethodByName(const AMethodName: string; p: PPointer; len: PInteger); var RttiContext: TRttiContext; RttiType: TRttiType; RttiMethod: TRttiMethod; Args: TArray<TValue>; begin RttiContext := TRttiContext.Create; try RttiType := RttiContext.GetType(Self.ClassType); RttiMethod := RttiType.GetMethod(AMethodName); if Assigned(RttiMethod) then begin SetLength(Args, 2); Args[0] := TValue.From<PPointer>(p); Args[1] := TValue.From<PInteger>(len); RttiMethod.Invoke(Self, Args); end else begin WriteLn(Format('Method ''%s'' not found.', [AMethodName])); end; finally RttiContext.Free; end; end; procedure Main; var MyObj: TMyObject; Data: Pointer; DataSize: Integer; ByteArray: TBytes; TotalBytes: Integer; begin MyObj := TMyObject.Create; try MyObj.CallMethodByName('TargetMethod', @Data, @DataSize); if (Data <> nil) and (DataSize > 0) then try TotalBytes := DataSize; SetLength(ByteArray, TotalBytes); // -------> Error occurs here Move(Data^, ByteArray[0], TotalBytes); finally FreeMem(Data); end; finally MyObj.Free; end; end; begin try Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. Kind regards André Share this post Link to post
Andre1 0 Posted Saturday at 02:57 PM Hi, I found the issue, it needs to be: Move(Data, ByteArray[0], TotalBytes); Kind regards André Share this post Link to post
Remy Lebeau 1623 Posted Sunday at 08:13 AM (edited) On 7/26/2025 at 7:57 AM, Andre1 said: I found the issue, it needs to be: Move(Data, ByteArray[0], TotalBytes); That is wrong. Your original call was correct. It is your Move() call inside of TargetMethod() that was wrong to begin with. It needs to be this instead: Move(Events[0], p^^, TotalSize); Inside of TargetMethod(): - p is a pointer to Main's Data variable. - p^ refers to the Data variable itself. - p^^ refers to the memory block that the Data variable is pointing at. The 2nd parameter of Move() takes a var reference to the memory it will write to. So it needs a reference to the memory block that the Data variable is pointing at, but you are giving it a reference to the Data variable itself. Thus, this call to Move() writes to the call stack of Main(), corrupting it. That is why the 2nd call to Move() inside of Main() crashes when it tries to read from the memory pointed at by the Data variable which resides in the now-corrupted call stack. You likely overwrote the Data variable during the 1st Move. Imagine how your Main() would need to use its Data and DataSize variables if it didn't have to pass them to TargetMethod() at all: procedure Main; var Data: Pointer; DataSize: Integer; ByteArray: TBytes; TotalBytes: Integer; begin ... GetMem(Data, ...); // <-- No ^ here Move(..., Data^, ...); // <-- 1 ^ here DataSize := ...; // <-- No ^ here ... if (Data <> nil) and (DataSize > 0) then try TotalBytes := DataSize; SetLength(ByteArray, TotalBytes); Move(Data^, ByteArray[0], TotalBytes); // <-- 1 ^ here finally FreeMem(Data); end; ... end; Now, because you added @ to Data and DataSize when passing them to TargetMethod(), you need an extra ^ on all accesses to Data and DataSize inside of TargetMethod(): GetMem(p^, TotalSize); // <-- 1 ^ here Move(..., p^^, ...); // <-- 2 ^ here len^ := ...; // <-- 1 ^ here Edited yesterday at 02:33 AM by Remy Lebeau 1 Share this post Link to post
Andre1 0 Posted Sunday at 04:47 PM Thank you so much Remy for your help. That make sense. Kind Regards André Share this post Link to post