![]() |
[Win32] Eintrag aus dynamischen Array löschen
Sicher kennen viele dass Problem, einen Eintrag aus einem dynamischen Array zu löschen. Delphi stellt keine vorgefertigte Funktion zur Verfügung, so dass man jedes mal eine eigene Löschroutine schreiben muss. Auch mich hat die Sache genervt und ich habe mich rangesetzt und eine Funktion geschrieben, die genau dies kann.
Delphi-Quellcode:
Ich will nicht behaupten, dass diese Funktion in allen Delphi-Versionen funktioniert, da direkt auf Typinformationen und Compilerinterne Funktionen zugegriffen wird, die sich von Version zu Version ändern können. Jedenfalls wurde die Funktion für D5, D6 und D7 erfolgreich getestet. Leider musste ich ein paar schmutzige Asm-Tricks einbauen (die ich nicht mehr erklären kann) da der Compiler mit einigen Registern gemacht hat, was er wollte. Und leider weiss ich auch nicht mehr, was alles im einzelnen bedeutet. Die Funktion habe ich schon vor längerer Zeit erstellt.
procedure DeleteArray(const ArrayPtr: Pointer; TypInfo: PTypeInfo; Index: Integer);
var NewElem: Integer; ElemSize: Integer; ElemAddr: Integer; ElemCount: Integer; begin Assert(TypInfo.Kind=tkDynArray,'Es werden nur Dynamische Arrays unterstützt'); // Elementgröße ermitteln ElemSize:=PInteger(PByte(Integer(TypInfo)+1)^+Integer(TypInfo)+2)^; // Elementanzahl ermitteln ElemCount:=PInteger(Integer(ArrayPtr^)-4)^; ElemAddr:=Integer(ArrayPtr^)+(Index*ElemSize); // Eintrag freigeben // Prüfen ob ein Finalize notwendig ist, dazu muss in der Type asm pushad mov esi,TypInfo xor eax,eax mov al,[esi+$01] add esi,eax add esi,$06 mov eax,[esi] test eax,eax jz @end mov edx,[eax] mov eax,ElemAddr call system.@finalize @end: popad end; MoveMemory(Pointer(ElemAddr),Pointer(ElemAddr+ElemSize),ElemSize*((ElemCount-1)-index)); NewElem:=ElemCount-1; // Letztes Element mit nullen füllen ZeroMemory(Pointer(Integer(ArrayPtr^)+(NewElem*ElemSize)),ElemSize); // Array verkleinern asm mov ebx,NewElem push ebx mov ecx,$00000001 mov edx,TypInfo mov eax,ArrayPtr call system.@DynArraySetLength add esp,$04 end; end; Vieles hab ich rausgefunden, in dem ich einfach SetLength irgendwo gemacht habe und mir den asm Output dazu angeschaut habe. Wie man sieht benutze ich auch Finalize um zum Beispiel bei Records enthaltene Strings freizugeben. Objekte müssen aber natürlich wie gewohnt selber freigegeben werden. Nun gut jetzt noch ein paar Worte zur Benutzung. Wichtig ist dass das Array als eigener Typ definiert wird.
Delphi-Quellcode:
Der Aufruf erfolgt dann relativ einfach:
type
TArrayType = Array of String;
Delphi-Quellcode:
Parameter 1 gibt die Adresse der Array-Variablen an. Paramater 2 die Typeninformation des Arrays. Erst dadurch bekomme ich Elementgrösse und benötigte Finalisierungsprozesse raus. Paramater 3 gibt schliessen den zu löschenden Eintrag an.
var
Arr : TArrayType; begin SetLength(Arr,100); Arr[10]:='Test'; DeleteArray(Addr(Arr),TypeInfo(TArrayType),10); So hoffe das diese Informationen hilfreich sind. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:41 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz