here is an example of function call with two (passed by ref) record parameters and two DWord parameters. The first DWord parameter is partially overwritten with the value of the previous record parameter (which stores an address). The code is a small part of the DynArrays library: https://libstock.mikroe.com/projects/vi ... /dynarrays
See the header of CopyFromDynArray function, where the high word of AIndex is overwritten with the value of ASrcArr (which is a pointer in this case, since the arg is passed by ref):
Code: Select all
function CopyFromDynArray(var ADestArr, ASrcArr: TDynArrayOfByte; {$IFDEF AppArch16} ADummy, {$ENDIF} AIndex, ACount: TDynArrayLength): Boolean;
Code: Select all
//Test code for simulator.
program SecondTestVarParam;
const
CMaxDynArrayLength = 65536; //bytes
HEAP_START: DWord = $001600; //make sure this is a valid address and is DWord aligned !
HEAP_SIZE: DWord = 7000; //Make sure enough memory is allocated. See the desktop application (simulator) for guidance.
type
TDynArrayLength = DWord;
PByte = ^far const code Byte;
PIntPtr = PByte;
TDynArrayOfByteContent = array[0..CMaxDynArrayLength - 1] of Byte;
PDynArrayOfByteContent = ^TDynArrayOfByteContent;
TDynArrayOfByte = record
Len: TDynArrayLength;
Content: PDynArrayOfByteContent;
//{$IFDEF IsDesktop}
// Initialized: string;
//{$ENDIF}
end;
//{$DEFINE AppArch16} ////////////////////////////// define this, to add an extra argument to some of the following functions, which will get overwritten
function Min32(a, b: LongInt): LongInt;
begin
if a < b then
Result := a
else
Result := b;
end;
procedure InitDynArrayToEmpty(var AArr: TDynArrayOfByte); //do not call this on an array, which is already allocated, because it results in memory leaks
begin
AArr.Len := 0; //this is required when allocating a new array
AArr.Content := nil; //probably, not needed, since Len is set to 0
{$IFDEF IsDesktop}
AArr.Initialized := 'init'; //some string, different than ''
{$ENDIF}
end;
function SetDynLength(var AArr: TDynArrayOfByte; ANewLength: TDynArrayLength): Boolean; //returns True if successful, or False if it can't allocate memory
var
OldPointer: {$IFDEF IsDesktop} PIntPtr; {$ELSE} DWord; {$ENDIF}
begin
{$IFDEF IsDesktop}
CheckInitializedDynArray(AArr);
{$ENDIF}
Result := True;
if ANewLength = 0 then
begin
if AArr.Len > 0 then
begin
{$IFnDEF IsDesktop}
{$IFDEF RoundAlloc}FreeMemRound{$ELSE}FreeMem{$ENDIF}(AArr.Content, AArr.Len);
{$ELSE}
{$IFDEF UsingDynTFT}
FreeMem(TPtrRec(AArr.Content), AArr.Len);
{$ELSE}
FreeMem(AArr.Content, AArr.Len);
{$ENDIF}
{$ENDIF}
end;
AArr.Len := 0;
Exit;
end;
if AArr.Len = 0 then
OldPointer := nil
else
OldPointer := PIntPtr(AArr.Content);
if (OldPointer = nil) and (AArr.Len > 0) then
Exit;
{$IFnDEF IsDesktop}
{$IFDEF RoundAlloc}GetMemRound{$ELSE}GetMem{$ENDIF}(AArr.Content, ANewLength);
if MM_error or (AArr.Content = nil) then //If compilers report that "MM_error" was not declared, then open MemManager library and uncomment MM_error header.
begin
Result := False;
Exit;
end;
if OldPointer <> nil then
{$IFDEF RedefineMemMove} MemMove32 {$ELSE} MemMove {$ENDIF}(AArr.Content, OldPointer, Min32(ANewLength, AArr.Len)); //OldPointer = src, AArr.Content = dest
{$ELSE}
try
{$IFDEF UsingDynTFT}
GetMem(TPtrRec(AArr.Content), ANewLength);
if MM_error or (AArr.Content = nil) then
begin
Result := False;
Exit;
end;
{$ELSE}
GetMem(AArr.Content, ANewLength);
{$ENDIF}
//AArr.Len is still the old array length. Only the Content field points somewhere else.
if OldPointer <> nil then
MemMove(AArr.Content, OldPointer, Min32(ANewLength, AArr.Len)) // the rest of the content is not initialized
except
Result := False;
end;
{$ENDIF}
if AArr.Len > 0 then
begin
{$IFnDEF IsDesktop}
{$IFDEF RoundAlloc}FreeMemRound{$ELSE}FreeMem{$ENDIF}(OldPointer, AArr.Len);
{$ELSE}
{$IFDEF UsingDynTFT}
FreeMem(TPtrRec(OldPointer), AArr.Len);
{$ELSE}
FreeMem(OldPointer, AArr.Len);
{$ENDIF}
{$ENDIF}
end;
AArr.Len := ANewLength;
end;
procedure FreeDynArray(var AArr: TDynArrayOfByte);
begin
{$IFDEF IsDesktop}
CheckInitializedDynArray(AArr);
{$ENDIF}
SetDynLength(AArr, 0);
end;
function CopyFromDynArray(var ADestArr, ASrcArr: TDynArrayOfByte; {$IFDEF AppArch16} ADummy, {$ENDIF} AIndex, ACount: TDynArrayLength): Boolean;
var
OldPointer: {$IFDEF IsDesktop} PIntPtr; {$ELSE} DWord; {$ENDIF}
begin
Result := True;
InitDynArrayToEmpty(ADestArr);
if ACount = 0 then
Exit;
if ASrcArr.Len = 0 then
begin
Result := False;
Exit;
end;
LATA := AIndex shr 16; //get the high word. /////////// The high word of AIndex is overwritten by the address of Arr, which is a global var.
LATB := AIndex; /////////////////////////////// AIndex should be 1, but the high word of AIndex is overwritten. !!!!!!!!!!!!!!
LATC := ACount shr 16; //============================= The high word of ACount is properly set to 0.
LATD := ACount; //============================= ACount should be 3.
if AIndex > ASrcArr.Len - 1 then
begin
Result := False;
Exit;
end;
if ACount > ASrcArr.Len - AIndex then
ACount := ASrcArr.Len - AIndex;
if not SetDynLength(ADestArr, ACount) then
begin
Result := False;
Exit;
end;
{$IFnDEF IsDesktop}
OldPointer := DWord(ASrcArr.Content) + AIndex;
{$ELSE}
OldPointer := Pointer(PtrUInt(ASrcArr.Content) + PtrUInt(AIndex));
{$ENDIF}
{$IFDEF RedefineMemMove} MemMove32 {$ELSE} MemMove {$ENDIF}(ADestArr.Content, OldPointer, ACount);
end;
function RemoveStartBytesFromDynArray(ACount: TDynArrayLength; var AArr: TDynArrayOfByte): Boolean;
var
PartialArr: TDynArrayOfByte;
NewLen: TDynArrayLength;
{$IFDEF AppArch16} Dummy: TDynArrayLength; {$ENDIF}
begin
Result := True;
if ACount >= AArr.Len then
begin
FreeDynArray(AArr);
Exit;
end;
if ACount = 0 then
Exit;
InitDynArrayToEmpty(PartialArr);
NewLen := AArr.Len - ACount;
{$IFDEF AppArch16}
Dummy := 0;
{$ENDIF}
if not CopyFromDynArray(PartialArr, AArr, {$IFDEF AppArch16} Dummy, {$ENDIF} ACount, NewLen) then //fixed by adding Dummy
begin
Result := False;
Exit;
end;
{$IFDEF RedefineMemMove} MemMove32 {$ELSE} MemMove {$ENDIF}(AArr.Content, PartialArr.Content, NewLen);
FreeDynArray(PartialArr);
Result := SetDynLength(AArr, NewLen);
end;
var
Arr: TDynArrayOfByte;
TempCount: DWord;
begin
MM_Init;
TempCount := 0;
TempCount := TempCount + 3;
InitDynArrayToEmpty(Arr);
SetDynLength(Arr, 4);
RemoveStartBytesFromDynArray(1, Arr); //remove one item from the beginning (i.e., the item at index 0)
LATF := Arr.Len; //this should be 3, not 4
repeat
until False;
end.
MCU: dsPIC33EP512MU810.
Thank you