...Make a dynamic array at runtime?
Author: Christian Poljac
{ This code can be changed to make an own array,
depending on how you want it.
An array can be made with the 2 Pointers -
one for the data offset-pointer and the second for TypeInfo.
Note that the ElementCount variable is usually '1'
With this script you can also initialize L/W Strings, Variants,
Records and Interface classes}
type
TForm1 = class(TForm)
Button1: TButton;
private
procedure _InitRecord(p: Pointer; typeInfo: Pointer);
procedure _InitArray(p: Pointer; typeInfo: Pointer; elemCount: Cardinal);
public
{ Public declarations }
end;
const
tkLString = 10;
tkWString = 11;
tkVariant = 12;
tkArray = 13;
tkRecord = 14;
tkInterface = 15;
tkDynArray = 17;
procedure tform1._InitRecord(p: Pointer; typeInfo: Pointer);
{$IFDEF PUREPASCAL}
var
FT: PFieldTable;
I: Cardinal;
begin
FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]));
for I := FT.Count-1 downto 0 do
_InitializeArray(Pointer(Cardinal(P) + FT.Fields[I].Offset), FT.Fields[I].TypeInfo^, 1);
end;
{$ELSE}
asm
{ -> EAX pointer to record to be initialized }
{ EDX pointer to type info }
XOR ECX,ECX
PUSH EBX
MOV CL,[EDX+1] { type name length }
PUSH ESI
PUSH EDI
MOV EBX,EAX // PIC safe. See comment above
LEA ESI,[EDX+ECX+2+8] { address of destructable fields }
MOV EDI,[EDX+ECX+2+4] { number of destructable fields }
@@loop:
MOV EDX,[ESI]
MOV EAX,[ESI+4]
ADD EAX,EBX
MOV EDX,[EDX]
MOV ECX,1
CALL _InitArray
ADD ESI,8
DEC EDI
JG @@loop
POP EDI
POP ESI
POP EBX
end;
{$ENDIF}
procedure tform1._InitArray(p: Pointer; typeInfo: Pointer; elemCount: Cardinal);
{$IFDEF PUREPASCAL}
var
FT: PFieldTable;
begin
if elemCount = 0 then Exit;
case PTypeInfo(typeInfo).Kind of
tkLString, tkWString, tkInterface, tkDynArray:
while elemCount > 0 do
begin
PInteger(P)^ := 0;
Inc(Integer(P), 4);
Dec(elemCount);
end;
tkVariant:
while elemCount > 0 do
begin
PInteger(P)^ := 0;
PInteger(Integer(P)+4)^ := 0;
PInteger(Integer(P)+8)^ := 0;
PInteger(Integer(P)+12)^ := 0;
Inc(Integer(P), sizeof(Variant));
Dec(elemCount);
end;
tkArray:
begin
FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]));
while elemCount > 0 do
begin
_InitializeArray(P, FT.Fields[0].TypeInfo^, FT.Count);
Inc(Integer(P), FT.Size);
Dec(elemCount);
end;
end;
tkRecord:
begin
FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]));
while elemCount > 0 do
begin
_InitializeRecord(P, typeInfo);
Inc(Integer(P), FT.Size);
Dec(elemCount);
end;
end;
else
Error(reInvalidPtr);
end;
end;
{$ELSE}
asm
{ -> EAX pointer to data to be initialized }
{ EDX pointer to type info describing data }
{ ECX number of elements of that type }
TEST ECX, ECX
JZ @@zerolength
PUSH EBX
PUSH ESI
PUSH EDI
MOV EBX,EAX // PIC safe. See comment above
MOV ESI,EDX
MOV EDI,ECX
XOR EDX,EDX
MOV AL,[ESI]
MOV DL,[ESI+1]
XOR ECX,ECX
CMP AL,tkLString
JE @@LString
CMP AL,tkWString
JE @@WString
CMP AL,tkVariant
JE @@Variant
CMP AL,tkArray
JE @@Array
CMP AL,tkRecord
JE @@Record
CMP AL,tkInterface
JE @@Interface
CMP AL,tkDynArray
JE @@DynArray
MOV AL,reInvalidPtr
POP EDI
POP ESI
POP EBX
JMP @Error
@@LString:
@@WString:
@@Interface:
@@DynArray:
MOV [EBX],ECX
ADD EBX,4
DEC EDI
JG @@LString
JMP @@exit
@@Variant:
MOV [EBX ],ECX
MOV [EBX+ 4],ECX
MOV [EBX+ 8],ECX
MOV [EBX+12],ECX
ADD EBX,16
DEC EDI
JG @@Variant
JMP @@exit
@@Array:
PUSH EBP
MOV EBP,EDX
@@ArrayLoop:
MOV EDX,[ESI+EBP+2+8] // address of destructable fields typeinfo
MOV EAX,EBX
ADD EBX,[ESI+EBP+2] // size in bytes of the array data
MOV ECX,[ESI+EBP+2+4] // number of destructable fields
MOV EDX,[EDX]
CALL _InitArray
DEC EDI
JG @@ArrayLoop
POP EBP
JMP @@exit
@@Record:
PUSH EBP
MOV EBP,EDX
@@RecordLoop:
MOV EAX,EBX
ADD EBX,[ESI+EBP+2]
MOV EDX,ESI
CALL _InitRecord
DEC EDI
JG @@RecordLoop
POP EBP
@@exit:
POP EDI
POP ESI
POP EBX
@@zerolength:
@Error:
end;
{$ENDIF}
printed from
www.swissdelphicenter.ch
developers knowledge base