Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Zugriffsverletzung bei TObjectlist.delete (https://www.delphipraxis.net/88712-zugriffsverletzung-bei-tobjectlist-delete.html)

ozz 19. Mär 2007 22:42


Zugriffsverletzung bei TObjectlist.delete
 
Hallo Leute,
ich habe irgendwie ein kleines Problem beim Löschen aus meiner TOjectlist. Rufe ich im Destructor das Delete auf, bekomme ich eine Zugriffsverletzung. Ersezte ich delete durch free (ohne Schleife) bekomme ich den gleichen Fehler. Ich blicks irgendwie nicht. :gruebel:

Dankbar für jeden Tip.

Delphi-Quellcode:
type TStreamlist= class (TObjectlist)
private
   FStreamObjectList:TObjectlist;
.....
constructor TStreamlist.create;
begin;
  inherited create;
  FStreamObjectList:=TObjectList.Create(true);
end;

destructor TStreamlist.destroy;
begin;
     while FStreamObjectList.Count>0 do
     begin
         FStreamObjectList.delete(0); {Zugriffsverletzung}
     end;
    inherited Destroy;
end;

Kedariodakon 19. Mär 2007 23:10

Re: Zugriffsverletzung bei TObjectlist.delete
 
1. Du machst es dir zu Kompliziert, wenn QwnObjects der TObjectList noch auf True ist (Standard) dann recht ein Clear aus, bzw. ein zerstören der Liste selber, diese gibt dann alle Objecte frei...

2. Wäre eine rückwärts laufende For-Sschleife bei weitem schneller...

3. Die Exception kommt aus dem Destructor des Objetes welches du da versuchst freizugeben... (denk ich, also durchlauf ihn mal mit dem Debugger...)

Bye Christian :zwinker:

Edit: Wie ich sehe, erstellst du die Liste sogar explezit nochmal mit OwnsObjects := True;, vondaher kannst du dir deinen ganzen Code da im destructor sparen, wenn du dir mal die Vorfahren deiner Liste anschaust, wirst du sehen, dass diese alle Objecte freigibt...

Ansatzpunkt wie gehabt Punkt 3. :wink:

Luckie 19. Mär 2007 23:39

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von Kedariodakon
2. Wäre eine rückwärts laufende For-Sschleife bei weitem schneller...

Das optimiert Delphi von alleine. ;)

Kedariodakon 20. Mär 2007 00:14

Re: Zugriffsverletzung bei TObjectlist.delete
 
Ok so genau weiß ich das nicht, hab auch gerade keine Lust zu schaun, was Delphi daraus macht... ;)
Aber rein ausm Gedächniss sollte die schon schneller sein und nicht den selben Code ausspucken.. =p

Bye Christian

Jelly 20. Mär 2007 06:21

Re: Zugriffsverletzung bei TObjectlist.delete
 
Warum leitest Du von TObjectList ab und erstellst dann in der Klasse noch eine TOBjectList (FStreamObjectList) :gruebel:

ozz 20. Mär 2007 07:06

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo zusammen,
Vielen Dank für die Tips.
ich habe noch etwas ausprobiert und dabei festgestellt, das mein FStreamObjectList.Count sinnvolle Werte enthält, aber ich immer noch eine Zugriffsverletzung bekomme,wenn ich FREE oder Delete oder Clear verwende.Ich dachte, ich gebe das Object an einer anderen Stelle schon frei. Finden konnte ich es bisher noch nicht. Kann es noch etwas anderes sein?


@Kedariodakon,
Danke dür die Erklärung. Ich habe es mal mit Clear, Free probiert. Der Fehler ist jedoch noch der gleiche. siehe oben!


@Jelly
Du hast natürich Recht. Kleiner Schnitzer.

Muehle 20. Mär 2007 07:25

Re: Zugriffsverletzung bei TObjectlist.delete
 
probiers mal damit (duerfte unabh. von der OwnObjects-Eigenschaft fkt.) :

destructor TStreamlist.destroy;
begin;
for i = 1 to FStreamObjectList.Count do
begin
FStreamObjectList.Items[i-1].free // jedes einzelne Objekt expl. freigeben
end;
FStreamObjectList.Clear(); // jetzt duerften nur noch nils da sein
inherited Destroy; // und zum Schluss noch das Basisdestroy

end;

IngoD7 20. Mär 2007 07:44

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von ozz
Ich dachte, ich gebe das Object an einer anderen Stelle schon frei. Finden konnte ich es bisher noch nicht. Kann es noch etwas anderes sein?

Auf die Schnelle überlegt: Eigentlich nicht.

In jedem Falle sollte dein TStreamlist-Destruktor die Liste FStreamObjectList selbst überhaupt auch mal freigeben. Diese Anforderung, gemeinsam mit der Tatsache, dass OwnsObjects TRUE ist, sollte folgendes ausreichen lassen:
Delphi-Quellcode:
destructor TStreamlist.destroy;
begin
    FStreamObjectList.Free;
    inherited Destroy;
end;
Ob dabei jettz noch der Fehler auftaucht, musst du mal gucken. Vielleicht ist die Auto-Freigabe der Liste auch so schlau und ignoriert irgendwie tote Referenzen (z.B. durch Abfangen der Execption). Das weiß ich jetzt nicht.

Zitat:

Zitat von ozz
@Jelly
Du hast natürich Recht. Kleiner Schnitzer.

Soooo natürlich ist das nun auch wieder nicht. Warum sollte eine Ableitung einer Liste nicht noch eine weitere Liste besitzen?

Aber wenn das jetzt geändert wurde, sieht die Geschichte ja völlig anders aus.

@ozz
Du solltest nochmal den jetzt aktuellen Code einstellen.

Hawkeye219 20. Mär 2007 08:00

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo,
Zitat:

Zitat von ozz
Ich dachte, ich gebe das Object an einer anderen Stelle schon frei. Finden konnte ich es bisher noch nicht.

vielleicht wurden die Objekte bereits automatisch freigegeben. TWinControls geben im Destruktor alle Controls frei, deren Parent sie sind.

Gruß Hawkeye

Kedariodakon 20. Mär 2007 08:10

Re: Zugriffsverletzung bei TObjectlist.delete
 
Welchen Destructor versucht er dann da aufzurufen? (Meine Glass versteckt sich schon seit gestern Abend...)
Was speicherst du in die Liste?


Bye Christian

Gruber_Hans_12345 20. Mär 2007 08:11

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von Luckie
Zitat:

Zitat von Kedariodakon
2. Wäre eine rückwärts laufende For-Sschleife bei weitem schneller...

Das optimiert Delphi von alleine. ;)

auch wenns etwas offtopic ist ... aber bist dir sicher, das delphi sowas optimieren kann?

immerhin muß der bei der while schleife doch immer den count abrufen da das ja eine funktion ist.
Bie der for schleife werden die start und end werte ja nur einmal abgefragt, von daher müßte sich schon ein unterscheid ergeben ... :gruebel:

Kedariodakon 20. Mär 2007 08:14

Re: Zugriffsverletzung bei TObjectlist.delete
 
würd ich auch behaupten... Auch wegen deinem angesprochenen Grund, ich denke sobald da ne Funktion im Spiel ist, wird da Delphi nicht mehr viel optimieren =p

Bye Christian

IngoD7 20. Mär 2007 08:54

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von Hawkeye219
TWinControls geben im Destruktor alle Controls frei, deren Parent sie sind.

Yepp - und ausserdem: TComponents geben bei ihrer eigenen Freigabe alle Components frei, deren Owner sie sind.

Jelly 20. Mär 2007 10:04

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von IngoD7
Zitat:

Zitat von ozz
@Jelly
Du hast natürich Recht. Kleiner Schnitzer.

Soooo natürlich ist das nun auch wieder nicht. Warum sollte eine Ableitung einer Liste nicht noch eine weitere Liste besitzen?

Natürlich geht das. Die Frage ist ob das in diesem Fall wirklich beabsichtigt war.

ozz 20. Mär 2007 20:03

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo Leute,
herzlichen Dank für die vielen Tips. Ich bin gerade noch dabei, diese durchzutesten. Bisher nur mit wenig Erfolg. Damit gehe sehr stark davon aus, das das Problem wo anders ist. Da ich es bis noch nicht geblickt habe, poste ich einfach mal den restlichen Code. Ist echt Mist, wenn man den Wald vor lauter Bäumen nicht mehr sieht.
Besten Dank!

Delphi-Quellcode:
type TStreamlist= class (TObject)
private
   FStreamObjectList:TObjectlist;
   function Get(Index: Integer): TStringstream;
   procedure Put(Index: Integer; const Value: TStringstream);

public
   constructor Create;
   destructor Destroy;override;
   function add: integer;
   function Additem(Item:TStringstream):integer;
   property items[Index: Integer]: TStringstream read Get write Put;
   function count: integer;
   procedure delete (index:integer);
   procedure clear;
end;

implementation

constructor TStreamlist.create;
begin;
  inherited create;
  FStreamObjectList:=TObjectList.Create(true);
end;

destructor TStreamlist.destroy;
var i:Integer;
begin;
  for i:= 1 to FStreamObjectList.Count do
    begin
        FStreamObjectList.Items[i-1].free // jedes einzelne Objekt expl. freigeben
    end;
  FStreamObjectList.Clear(); // jetzt duerften nur noch nils da sein
  inherited Destroy; // und zum Schluss noch das Basisdestroy
end;

function TStreamlist.add: integer;
var TagType: TStringstream;
begin
   TagType:=TStringstream.Create('');
   Result:= FStreamObjectList.add(TagType);
end;

function TStreamlist.Additem(Item: TStringstream): Integer;
var TagType: TStringstream;
begin
    TagType:=TStringstream.Create('');
    TagType:=Item;
    Result:= FStreamObjectList.add(TagType);
end;

function TStreamlist.Get(Index: Integer):TStringstream;
begin;
    result:= TStringstream(FStreamObjectList.Items[Index]);
end;

procedure TStreamlist.Put(Index: Integer; const Value: TStringstream);
begin
    FStreamObjectList[Index]:=Value;
end;

function TStreamlist.count: integer;
begin
    result:=FStreamObjectList.count;
end;

procedure TStreamlist.Delete(index:integer);
begin
    FStreamObjectList.Delete(index);
    FStreamObjectList.Capacity := FStreamObjectList.Count; //Speicher Freigeben
end;

procedure TStreamlist.clear;
begin
 while FStreamObjectList.Count >0 do
 begin
   FStreamObjectList.Delete(0);
 end;
end;


end.

Luckie 20. Mär 2007 22:07

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von Kedariodakon
würd ich auch behaupten... Auch wegen deinem angesprochenen Grund, ich denke sobald da ne Funktion im Spiel ist, wird da Delphi nicht mehr viel optimieren =p

Ups, ich dachte, das wäre eine for-Schleife gewesen.

ozz 21. Mär 2007 06:33

Re: Zugriffsverletzung bei TObjectlist.delete
 
*push*

Jelly 21. Mär 2007 06:36

Re: Zugriffsverletzung bei TObjectlist.delete
 
Also wenn das wirklich die gesamte Klasse ist, behaupte ich weiterhin dass, dass die Ableitung von TObjectList schon fast alles löst was Du versuchst komplitziert nachzubasteln. Hier mal ein ähnliches Beispiel:

Delphi-Quellcode:
unit untLieferschein;

interface
uses classes, windows, contnrs, sysutils ;

type
  TLieferschein = class
  TLieferscheine = class (TObjectList)
  private
    function GetItem(Index: Integer): TLieferschein;
    procedure SetItem(Index: Integer; const Value: TLieferschein);
  public
     constructor Create (AConnection : TADOConnection) ; overload ;
     property Items[Index: Integer]: TLieferschein read GetItem write SetItem; default;
  end;

implementation

function TLieferscheine.GetItem(Index: Integer): TLieferSchein;
begin
     Result := (inherited Items[Index]) as TLieferSchein ;
end;

procedure TLieferscheine.SetItem(Index: Integer; const Value: TLieferSchein);
begin
     inherited Items[Index] := Value ;
end;

end.

Jelly 21. Mär 2007 06:36

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von ozz
*push*

Lass bitte nach wenigen Stunden das Pushen. Das wird hier nicht sehr geschätzt.

IngoD7 21. Mär 2007 08:28

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zur Erinnerung:

1.) FStreamObjectList freigeben!
Zitat:

Zitat von IngoD7
In jedem Falle sollte dein TStreamlist-Destruktor die Liste FStreamObjectList selbst überhaupt auch mal freigeben.

2.) Mache es dir einfach:
Zitat:

Zitat von IngoD7
Diese Anforderung, gemeinsam mit der Tatsache, dass OwnsObjects TRUE ist, sollte folgendes ausreichen lassen:
Delphi-Quellcode:
destructor TStreamlist.destroy;
begin
    FStreamObjectList.Free;
    inherited Destroy;
end;


Kedariodakon 21. Mär 2007 10:23

Re: Zugriffsverletzung bei TObjectlist.delete
 
Das Problem wird wohl eher in: TStringstream zu finden sein, was immer das auch ist...

Bye Christian

IngoD7 21. Mär 2007 10:43

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von Kedariodakon
Das Problem wird wohl eher in: TStringstream zu finden sein, was immer das auch ist...

Ist das auf mein Vorposting bezogen?
Nun, mein Posting muss mit dem Problem auch nicht unbedingt zu tun haben.
Es wäre trotzdem reichlich sinnig, die im Konstruktor erzeugte Liste später im Destruktor auch wieder freizugeben (und nicht nur die Listeninhalte).

TStringStream gibt es (in der Unit Classes - siehe OH).

ozz 21. Mär 2007 16:07

Re: Zugriffsverletzung bei TObjectlist.delete
 
Danke für die Hilfe IngoD7,Kedariodakon und Jelly.
Leider besteht das Problem immer noch (auch mit Jelly Ableitung).Damit kann ich aber das Problem zumindestens in der Unit ausschließen. Ich habe noch ein kleinen Schnitzer gefunden. Daher muß in nochmal in Ruhe schauen.

@IngoD7
Free habe ich schon mal propiert. Ist in der Liste oben (Original Post)

@Jelly
Danke für das Code Snippet. Ich lerne gerne immer dazu.... auch was das pushen angeht. :shock: Ich werde mich dran halten.:!:

Kedariodakon 21. Mär 2007 16:34

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von IngoD7
TStringStream gibt es (in der Unit Classes - siehe OH).

Ah ok, hatte damit noch nicht gearbeitet =p


Aber mal so nebenbei, was ist das da für ein Käse?
Delphi-Quellcode:
function TStreamlist.Additem(Item: TStringstream): Integer;
var TagType: TStringstream;
begin
    TagType:=TStringstream.Create('');
    TagType:=Item;
    Result:= FStreamObjectList.add(TagType);
end;
Warum wird da eigendlich ein neuer Stream erstellt, aber schlussendlich der alte hinzugefügt?

Nunju, vielleicht magst du uns ja ein Beispiel Projekt anhängen, dann kann man ja mal drüberschaun, wenn zeit ist ;)

Bye Christian

ozz 21. Mär 2007 16:37

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo Leute ich habe es gefunden. Nochmal vielen Dank für die vielen Tips.Falls es jemand wissen will, hier die Ursache :wall:
Delphi-Quellcode:
procedure ThreadResult(ContentStream: TStringStream);
....
    Content:=TStringStream.Create('');
    Content.Position:=0;
    ContentStream.Position:=0;
    Content.CopyFrom(ContentStream,ContentStream.Size);
    index:=FResultlist.Add(Content);//<-war vorher ContentStream
...

ozz 21. Mär 2007 16:41

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo Kedariodakon,
eigentlich sollte der "Käse" nur den Stream umkopieren, die aus einem Thread kommen. Der wird zerstört,wenn der Thread beendet wird. Das war je in diesem Fall genau das Problem. Prinzip wie im vorheriges Posting.

Kedariodakon 21. Mär 2007 16:46

Re: Zugriffsverletzung bei TObjectlist.delete
 
Auf gut deutsch du hast das falsche in die Liste getan, right? :mrgreen:

Bye Christian

ozz 21. Mär 2007 16:53

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo Kedariodakon,
GENAU! :wall:

IngoD7 21. Mär 2007 17:50

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von ozz
@IngoD7
Free habe ich schon mal propiert. Ist in der Liste oben (Original Post)

Ja, glaube ich das denn ...? :roll:
Du hast es nicht probiert. Lies doch mal, was genau ich geschrieben habe.

Nochmal:
Du hast in deiner Klasse ein Objekt vom Typ TObjectList (FStreamObjectList). Dieses Objekt wird im Konstruktor erzeugt:
Delphi-Quellcode:
constructor TStreamlist.create;
begin;
  inherited create;
  FStreamObjectList:=TObjectList.Create(true);
end;
Dieses Objekt FStreamObjectList muss auch wieder freigegeben werden!
Das geht so:
Delphi-Quellcode:
destructor TStreamlist.destroy;
begin
    FStreamObjectList.Free;
    inherited Destroy;
end;
Und wenn du das dann endlich so tust, dann kannst du dir deinen Code sparen, mit dem du die Elemente deiner Liste freigibst (das ist nicht die Liste selbst, es sind lediglich die Elemente!). Denn das Freigeben der Objektliste FStreamObjectList gibt automatisch die Elemente dieser Liste mit frei.

Ufff ... :|

ozz 21. Mär 2007 18:35

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo IngoD7,
herzlichen Dank für den Hinweis. Ich habe dich verstanden und auch dein Anliegen. Ich habe die Test genau so gemacht, wie du es vorgeschlagen hast. Ich habe auch das Free eingebaut und das Delete entfernt. Danke nochmal!

IngoD7 21. Mär 2007 18:53

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von ozz
Hallo IngoD7,
herzlichen Dank für den Hinweis. Ich habe dich verstanden und auch dein Anliegen. Ich habe die Test genau so gemacht, wie du es vorgeschlagen hast. Ich habe auch das Free eingebaut und das Delete entfernt. Danke nochmal!

Test? :shock:

Postest du bitte mal deinen aktuellen Destruktor TStreamlist.destroy? :wink:

ozz 22. Mär 2007 17:24

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo IngoD7,
ich habe mich in letzter Instanz entschieden, den Tip von Jelly angenommen. Daher habe ich jetzt keinen eigenen Destructor mehr, sondern den der Klasse TObjectlist. Den Test, nach dem du gefragt hast, habe ich vor diese letzten Änderung gemacht. Momentan sieht die Klasse so aus.


Delphi-Quellcode:
type TStreamlist= class (TObjectlist)
private
   function GetStream(Index: Integer): TStringstream;
   procedure PutStream(Index: Integer; const Value: TStringstream);

public
   function add: integer;overload;
   function Add(Item:TStringstream):integer;overload;
   property items[Index: Integer]: TStringstream read GetStream write PutStream;
end;

implementation

function TStreamlist.add: integer;
var TagType: TStringstream;
begin
   TagType:=TStringstream.Create('');
   Result:= inherited add(TagType);
end;

function TStreamlist.Add(Item: TStringstream): Integer;
begin
    Result:= inherited add(item);
end;

function TStreamlist.GetStream(Index: Integer):TStringstream;
begin;
    result:= TStringstream(inherited Items[Index]);
end;

procedure TStreamlist.PutStream(Index: Integer; const Value: TStringstream);
begin
    inherited items[Index]:=Value;
end;

end.

Jelly 22. Mär 2007 18:12

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von ozz
Delphi-Quellcode:
function TStreamlist.add: integer;
var TagType: TStringstream;
begin
   TagType:=TStringstream.Create('');
   Result:= inherited add(TagType);
end;

Das geht sogar noch kürzer :wink:
Delphi-Quellcode:
function TStreamlist.add: integer;
begin
   Result:= inherited add(TStringstream.Create(''));
end;

Achim Kalwa 22. Mär 2007 18:39

Re: Zugriffsverletzung bei TObjectlist.delete
 
Hallo,

ich hab' jetzt nicht alle Antworten gelesen und weiß auch nicht, was dieses Konstrukt genau anstellen soll. Aber das hier springt mir doch ins Auge:
Zitat:

Zitat von ozz
Delphi-Quellcode:
procedure TStreamlist.clear;
begin
 while FStreamObjectList.Count >0 do
 begin
   FStreamObjectList.Delete(0);
 end;
end;

Warum machst Du nicht einfach folgendes:
Delphi-Quellcode:
procedure TStreamlist.clear;
begin
  FStreamObjectList.Clear;
end;
Das löscht ebenfalls alle Objekte in FStreamObjectList. Und da FStreamObjectList der Eigentümer aller enthaltener Objekte ist, werden diese alle auch vorher brav mit Free freigegeben.

Wenn Du das -- aus irgend einem Grund -- trotzdem "von Hand" machen möchtest, dann musst Du nach dem Free() den Eintrag in der Liste auf NIL setzen. Der nachfolgende Aufruf von Clear() durchläuft ja intern noch einmal die Liste und versucht, die Items freizugeben... *Bumm*. Dass die Items von Dir schon freigeben wurden, kann die Liste ja nicht wissen.

Delphi-Quellcode:
destructor TStreamlist.destroy;
var i:Integer;
begin;
  for i:= FStreamObjectList.Count-1 downto 0 do // Rückwärts laufen
  begin
    FStreamObjectList.Items[i].free    // jedes einzelne Objekt expl. freigeben
    FStreamObjectList.Items[i] := nil; // Referenz entfernen!!!
  end;
  FStreamObjectList.Clear(); // Alle Items entfernen.
  inherited Destroy; // und zum Schluss noch das Basisdestroy
Aber wie schon geschrieben: Der ganze Code ist hyperfluid: TObjectList.Clear() macht das alles schon intern!

Achim

Jelly 22. Mär 2007 18:54

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von kalwados
ich hab' jetzt nicht alle Antworten gelesen und weiß auch nicht, was dieses Konstrukt genau anstellen soll.
...
Warum machst Du nicht einfach folgendes:
Delphi-Quellcode:
procedure TStreamlist.clear;
begin
  FStreamObjectList.Clear;
end;

Tja, hättest Du vielleicht machen können. Das hätt Dir einiges an Tipparbeit erspart :mrgreen:

IngoD7 23. Mär 2007 07:31

Re: Zugriffsverletzung bei TObjectlist.delete
 
Zitat:

Zitat von ozz
Hallo IngoD7,
ich habe mich in letzter Instanz entschieden, den Tip von Jelly angenommen. Daher habe ich jetzt keinen eigenen Destructor mehr,

... sondern du leitest jetzt wieder direkt von TComponentList ab und hast vor allen Dingen kein extra Feld FStreamObjectList mehr.
Das ist neu. Das hättest du zwischendurch mal schreiben können. :?
Dann hätte ich mir auch Tipparbeit sparen können. :wink:


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz