![]() |
Registrieren von Klassen
Hallo,
ich erzeuge in meiner Anwendung eine Klasse 'PDInterface'. In dieser möchte ich alle für meine Anwendung benötigten Klassen registrieren. Ist das möglich?
Delphi-Quellcode:
Leider schlägt das Registrieren mit eine Schutzverletzung fehl.
unit PDInterface;
... constructor TPDInterface.Create(Owner: TComponent); // Owner ist die Anwendung var I: Integer; aClass: TPersistentClass; ClassName: String; begin FApplication:= Owner; FDatabase:= TmyDatabase.Create(Owner); For i:=0 to Length(FClassArray) -1 do begin // Erzeugt Einträge aus den TabellenNamen der DB FClassArray[TClassIndex(i)]:= Database.FTableArray[i]; // Ermittelt den aktuellen Tabellennamen und stellt ein'TPD' voran, welches dann den Namen // der Klasse ergibt ClassName:= 'TPD'+FClassArray[TClassIndex(i)]; // Casten auf persistente zu registrierende Klasse aClass:= TPersistentClass(ClassName); // Versuch die aktuelle Klasse zu registrieren RegisterClass(aClass); end // for end; Kann jemand helfen? |
Re: Registrieren von Klassen
Hi,
ist Deine Klasse von TPersistent abgeleitet bzw. ist die RTTI ({$M+}) dafür aktiviert? mfG mirage228 |
Re: Registrieren von Klassen
Hi,
ja die zu registrierenden Klassen sind alle vom Typ TPersistent bzw. Unterklassen:
Delphi-Quellcode:
TPersistent
| TPDObject | TPDMeineZuRegistrierendeKlasse |
Re: Registrieren von Klassen
Hi,
dann versuch mal die Klasse im initialization Abschnitt der Unit zu registrieren. mfG mirage228 |
Re: Registrieren von Klassen
Hi,
das war meine Frage: Kann ich das NUR dort? Denn es müssen vorher erst einige Klassen zur Verfügung stehen, die die zu registrierenden Klassen ermitteln...!? |
Re: Registrieren von Klassen
Zitat:
Achso, das weiss ich nicht. Jedoch wurden bei den Programmen, die ich gesehen habe, die Klassen im initialization Abschnitt initialisiert. Noch 2 Fragen: ist aClass eventuell = nil ? Hast Du schon versucht mit Debug DCUs zu kompilieren und auch in Delphi Sourcen mit reingetraced? mfG mirage228 |
Re: Registrieren von Klassen
Delphi-Quellcode:
:shock: Du kannst nicht einfach einen String auf eine metaklasse casten :wink: ..abgesehen davon solltest du diese variable nicht ClassName nennen, da dies eine klassen-methode von TObject ist.
var...
ClassName: String; ... aClass:= TPersistentClass(ClassName); Du brauchst hier schon explizit die klasse. das was du da versuchst, geht auf keinen fall...und wenn es gehen würde, dann bräuchtest du die klasse ja nicht mehr registrieren. Aber erzähl doch mal was du erreichen willst? |
Re: Registrieren von Klassen
Hallo,
ich möchte in die für meine Anwendung benötigten Klassen automatisch generieren. Dazu existiert für jede DB-Tabelle eine eigene Klasse. Bei der Initialisierung der Anwendung oder beim Erzeugen des Hauptformulars möchte ich die benötigten Klassen erzeugen. Möglichst über eine einzige Prozedur, die über ein Array der Tabellennamen iteriert. Ich bin zur Zeit nicht an meinem Arbeitsplatz, so dass ich erst morgen wieder genauer auf das Problem eingehen kann... |
Re: Registrieren von Klassen
Hallo,
nun noch einaml zurück zum Thema. Ich möchte in einer Klasse alle für die Konfiguration erforderlichen Daten ablegen. Dazu gehören auch Prozeduren und Funktionen, die mir zur Laufzeit Konfigurationsarameter ermitteln. Hier mal etwas Code:
Delphi-Quellcode:
Dazu müssen die Klassen allerdings registriert sein:
unit ConfigFile;
interface uses SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs; type TConfigFile = class (TObject) ... TPDObjectClass = class of TPersistent; { Hier müssen alle in der Datenbank enthaltenen Tabellen angegeben werden. } TClassIndex = ( {1} Ansprechpartner, {2} Auftrag, {3} auftragstatus, {4} ... {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16} {17} {18} {19} {20} {21} {22} {23} {24} {25} {26} {27} ); // Beinhaltet die Namen der Tabellen. Um mit einer Klasse zu Arbeiten, wird die // entsprechende Klasse aus dem Array per Tabellenname oder per Index gesucht und ein 'TPD' // vorangestellt, um den Namen der Klasse zu erhalten TClassArray= array[Ansprechpartner..zustaendigkeit] of String; procedure Register; implementation // Hier stehen statische Parameter const C_DatabaseName = 'Name'; C_Host = 'Host'; ... //Das 'ClassArray' lade ich zur Laufzeit aus der DB (TableList): for i:=0 to TableList.Count-1 do ClassArray[TClassIndex(i)]:= List.Strings[i]; ... //Nun kann ich folgendes machen: function TPDInterface.GetPDObject(Index: Integer): TPDObject; var pdClass: TPDObjectClass; begin pdClass:= findClass('TPD'+ClassArray[TClassIndex(index)]); //pdClass:= findClass('TPDAnsprechpartner'); if FPDObjects[index]= NIL then FPDObjects[index]:= TPDObject.Create(Database); result:= FPDObjects[index];
Delphi-Quellcode:
Da ich aber erst zur Laufzeit auf die Config-Klasse zugreifen kann, muss ich das Registrieren also an einer anderen Stelle tun als im Initialization-Teil.
initialization
RegisterClasses([TPDAnsprechpartner,TPDAuftrag, TPDAuftragstatus,...]); Ich dachte also das könnte ich auch beim Erzeugen meines Hauptformulars tun:
Delphi-Quellcode:
Mein Hauptanliegen ist es alle Konfigurationsparameter in einer eigenen Klasse zu halten (ConfigFile).
unit main
... constructor TForm1.FormCreate(Sender: TObject); var I: Integer; aClass: TPDObjectClass; ClassName: String; begin FApplication:= Owner; // Hier werden alle Parameter des ConfigFiles geladen und die TabellenNamen der DB ermittelt FDatabase:= TmyDatabase.Create(Owner); For i:=0 to Length(FClassArray) -1 do begin FClassArray[TClassIndex(i)]:= Database.FTableArray[i]; ClassName:= 'TPD'+FClassArray[TClassIndex(i)]; aClass:= TPDObjectClass(ClassName); RegisterClass(aClass); end // for end; Kann jemand dazu Stellung nehmen? Kann jemand helfen? |
Re: Registrieren von Klassen
Hallo barnti,
klingt nach einem interessanten Vorhaben, dass ich in Delphi (außerhalb der VCL) in veröffentlichten Projekten mit Quelltext bisher nur bei ![]() Generell habe ich zur Lösung ähnlicher Probleme häufig diesen Ansatz gesehen:
Vielleicht solltest Du Dir noch einmal das ![]() ![]() |
Re: Registrieren von Klassen
Hallo Choose,
danke für Deine Antwort! Ich arbeite bereits mit Entwurfsmustern. Die Abstrakte Fabrik und das Singleton-Muster sind bereits verbaut. Ich habe dies lediglich wegen der Übersichtlichkeit weggelassen. Der Punkt ist: Wenn ich die Klassen in meiner Unit 'Main' registriere, muss ich bei der Erstellung einer neuen Tabelle in der DB und der Erstellung der zugehörigen Klasse für die Behandlung an zwei Stellen Veränderungen vornehmen: ConfigFile: Tabellenname als ArrayIndex hinzufügen UND In der Unit 'Main': Zu registrierende Klasse im Initialization-Abschnitt angeben. Mein Gedanke war es alles an einer Stelle(in einer Unit) vorzuhalten. Ob das in der Registrierung geschieht oder in einer Klasse sollte nicht entscheidend sein. So wie ich dich verstehe sollte(MUSS) das Registrieren der Klassen in den Initialization-Abschnitt. Kommt in der DB eine neue Tabelle hinzu, dann ist demnach folgendes zu tun: 1. Klasse für die Tabelle Implementieren 2. Tabellenindex in das ClassArray aufnehmen 3. Klasse im Initialization-Teil registrieren Dann kann ich auch mit dem folgenden Konstrukt arbeiten
Delphi-Quellcode:
Ist das soweit richtig gedacht?
function TPDInterface.GetPDObject(Index: Integer): TPDObject;
var pdClass: TPDObjectClass; begin // Klasse über Idex des Arrays ansprechen(theoretisch geht dann auch der Name der Tabelle) pdClass:= findClass('TPD'+ClassArray[TClassIndex(index)]); //pdClass:= findClass('TPDAnsprechpartner'); if FPDObjects[index]= NIL then FPDObjects[index]:= PDClass.Create(Database); result:= FPDObjects[index]; |
Re: Registrieren von Klassen
Der Ort der Registrierung ist im Wesentlichen egal, sie sollte lediglich chronoligisch gesehen vor der Verwendung stattfinden...
Mir ist der Sinn hinter dem ClassArray nicht ganz klar. In Deinem Kommentar schreibst Du, dass hier zu jeder Tabelle (Entität) eine geeignete Klasse registriert sein sollte, und hinterlegst stattdessen eine textuelle Bezeichnung, die der der Entität zu entsprechend scheint ("Ansprachpartner", "Auftrag", etc.). Dies ist nach meinem Empfinden eine redundante Information, weil sie bereits in Deinem Datenbankschema existiert, oder nicht? Was spricht also dagegen, die Schemainformationen zu nutzen und die Bezeichnung Deiner Entität als Key für Dein Mapping zu verwenden. In der Configuration könnte nun hinterlegt werden, wie ein Schlüssel, zB "Ansprechpartner" auf einen Klassennamen, hier zB "TPDAnsprechpartner" abbilden soll. Falls Du in Deiner Konfiguration (zB in einer externen Datei) keine explizite Angabe machst, könnte dieses Mapping jedoch durch einfaches Konkatenieren geschehen, also etwa in der Art
Delphi-Quellcode:
Existieren nun drei verschiedene geeignete Implementierungen für die Entität "Ansprechpartner", kann zur Laufzeit entschieden werden, ob die Klasse "TPDAnsprechpartner" oder eine andere durch ihren Klassennamen konfigurierte Klasse verwendet werden sollte.
function TConfiguration.GetClassNameFromKey(const AKey: string): string;
begin if KeyWasConfigured(AKey) then Result := GetValueFromKey(AKey) else Result := Format('%s%s%s', [FPrefix, FKey, FPostfix]); end; Interessant ist, dass Du mithilfe des Datenbankschemas eine Prüfung durchführen kannst, die sicherstellt, dass bei einer Null-Konfiguration (ohne angepasstes Mapping) alle benötigten Klassen existieren (registriert worden sind), bzw beim Laden einer Konfiguration mit Anpassungen entsprechend verfährt und unter Ausgabe eines Hinweises für ggf nicht vorhandene Klassen auf den Null-Wert verfällt. |
Re: Registrieren von Klassen
Hallo Choose,
ist ich weiß nicht, ob ich alles verstanden habe. Noch einmal zur Erklärung: Für jede Tabelle in der DB soll eine Klasse existieren. Dafür muss beim 'Laden' der Anwendung folgendes geschehen: 1.Klassen registrieren: Stehen in Initialization-Teil Das genügt für den Start der Anwendung. Möchte ich jetzt mit einer Tabelle arbeiten, so wird das in der Anwendung ausgelöst: Der Benutzer wählt eine Tabelle mit Namen oder den Index der Tabelle und deren Inhalt in einem z.B. TDBGrid anzeigen zu lassen. Dieses Laden der Tabelle sollte generisch geschehen. Dazu wird entweder der Index oder der Tabellenname benötigt:
Delphi-Quellcode:
Um das zu ermöglichen sind die Tabellen in im Array 'ClassArray' mit dem Namen gespeichert. In der Funktion soll damit also ein Objekt vom Typ 'findClass('TPD'+ClassArray[TClassIndex(index)]);' erzeugt werden.
function TPDInterface.GetPDObject(Index: Integer): TPDObject;
var pdClass: TPDObjectClass; begin // Klasse über Idex des Arrays ansprechen(theoretisch geht dann auch der Name der Tabelle) pdClass:= findClass('TPD'+ClassArray[TClassIndex(index)]); //pdClass:= findClass('TPDAnsprechpartner'); if FPDObjects[index]= NIL then FPDObjects[index]:= PDClass.Create(Database); result:= FPDObjects[index]; Deshalb das Array. Ist das verständlich? Oder denke ich umständlich? Ich will lediglich die Erzeugung generisch geschehen lassen... Das Mapping geschieht mit Hilfe des 'ClassArray'. Das Datenbankschema lässt sich nicht einfach indiziert ansprechen deshalb das Array... |
Re: Registrieren von Klassen
Der Benutzer öffnet eine Tabelle mit der Bezeichnung "Ansprechpartner" und Du möchtest daraufhin ein Objekt der geeigneten Klasse erzeugen. Hierzu könntest Du den Klassennamen mithilfe einer Konfiguration (Mapping) ermitteln, indem Du den Namen der Tabelle als Schlüssel übergibst.
Delphi-Quellcode:
Im Normalfall (es wurde kein Spezielles Mapping hinterlegt) erzeugtt die Konfiguration den Klassennamen durch Aneinanderhängen von fest definierten Teilstrings. Der Inhalt von myClassName lautet in Deinem Fall also "TPDAnsprechpartner". Um nun ein Objekt erzeugen zu können, ist es notwendig, vom ermittelten Klassennamen auf die Klasse selbst zu schließen. Das Geschieht mithilfe Deiner Registratur (oder, falls Du RegisterClass verwendest mit FindClass) in der Art
myClassName := Configuration.GetClassNameFromKey('Ansprechpartner');
Delphi-Quellcode:
Falls Du FindClass verwendest ist hier natürlich ein Cast auf die von Dir verwendete Klasse notwendig, um den passenden virtuellen(!) Konstruktur aufrufen zu können.
myClass := Registration.GetClassFromName(myClassName);
Anschließend erzeugst Du ein Exemplar der nun bekannten Klasse durch einen Aufruf des Konstruktors und übergiebst ihm alle notwendigen Parameter (zB Tabelle, Rechte, etc.)
Delphi-Quellcode:
Das Erzeugen geschieht also generisch und das Mapping -so von Dir beschrieben- kann im Regelfall ebenfalls ohne weitere Anpassungen geschehen. Erst, wenn Klassen- und Tabellenname nicht länger gemäß des Musters übereinstimmen, ist es notwendig, die Konfiguration anzupassen, was zB einmalig im Konstruktor oder eine andere Zuweisungsform geschehen könnte.
Result := myClass.Create(myContext);
Im Allgemeinen gilt jedoch: Kommt eine Tabelle hinzu, die mithilfe einer bereits verwendeten Klasse bearbeitet werden kann, braucht nur die Konfiguration angepasst werden oder -der Regelfall- kommt eine neuartige Tabelle hinzu, wird eine neue Klasse angelegt, in der Unit ihrer Implementierung registriert wird. Dies ist lediglich eine Idee, die auf dem, was ich aus Deiner Aussage verstanden habe, fußt... |
Re: Registrieren von Klassen
Hi Choose,
ok das habe ich soweit geblickt. Um das Ganze noch einmal zu festigen:
Delphi-Quellcode:
Wenn ich jetzt in meiner Anwendung mit der Tabelle 'Ansprechpartner' arbeiten will, geschieht folgendes:
TPersistent
| TPDObject // Allgemeine Klasse, die die gameinsamen Eigenschaften aufnimmt | TPDAppObject // Klaase, die für diese Anwendung spezifische Eigenschaften beinhaltet | TPDAnsprechpartner // Spezielle Eigenschaften und Methoden für die Behandlung einer speziellen Tabelle
Delphi-Quellcode:
Das ist damit ein Problem. Wie der Objekthierarchie zu entnehmen ist, ist 'TPDAnsprechpartner' ein spezialisierteres Objekt. Wie Speichere ich meine Speziellen Objekte? So geht es nicht! Und das Erzeugen klappt so auch nicht.
// Interface über das das Arbeiten mit einer Klasse veröffentlicht wird(Schnittstelle)
function TPDInterface.GetPDObject(Index: Integer): TPDObject; var pdClass: TPDObjectClass; begin // ergibt 'Ansprechpartner' pdClass:= findClass('TPD'+ClassArray[TClassIndex(index)]); // Array das Objekte vom Typ 'TPDObject speichert' if FPDObjects[index]= NIL then FPDObjects[index]:= PDClass.Create(Database); result:= FPDObjects[index]; Hier sollte ja letztendlich stehen:
Delphi-Quellcode:
So klappt die generische Erzeugung nicht.
function TPDInterface.GetPDObject(Index: Integer): TPDObject;
var pdClass: TPDObjectClass; begin pdClass:= findClass('TPD'+ClassArray[TClassIndex(index)]); // TPDAnsprechpartner.Create(Database); if FPDObjects[index]= NIL then FPDObjects[index]:= PDClass.Create(Database); result:= FPDObjects[index]; |
Re: Registrieren von Klassen
Der Signatur von FindClass ist zu entnehmen, dass der Rückgabewert vom Typ TPersistentClass. Du musst ihn deshalb auf den von Dir benötigten Casten (ähnlich wie es in Delphi bei Objekten in Ereignisbehandlungsroutinen gemacht wird, wenn statt Sender als TObject die Schnittstelle von TButton benötigt wird) oder eine eigene Registratur implementieren, damit Deine Lösung typsicher wird.
Delphi-Quellcode:
nun kann der in TPDObjectClass eingeführte Konstruktor verwendet werden.
var
myClass: TPDObjectClass; begin myClass := TPDObjectClass(FindClass('TPDAnsprechpartner')); Achtung: Sollte der Konstruktor in einem Nachkommen von TPDObjectClass abermals überschrieben worden sein und ist er in TPDObjectClass nicht als virtuell markiert worden, wirst Du hier Probleme bekommen. Sieh Dir einmal den Ansatz von TComponent im Hinblick auf die Konstruktoren der Erben an, damit Du siehst, was ich meine. |
Re: Registrieren von Klassen
Hi Choose,
das ist richtig. Nur habe ich dann das folgende Problem:
Delphi-Quellcode:
Dies leht der Compiler aber ab!
unit PDInterface;
... type // Metaklassenvariable TPDObjectClass = class of TPDObject; TClassIndex = (Ansprechpartner,Auftrag,auftragstatus,benutzer,bereich,beschaedigung,config, container,dbdesigner4,dokument,foto,hafenplatz,kolli,Kunde, packliste,partie,partiestatus,partiekarte,pending,position,produktbeschreibung, produktgruppe,sql,unterpartie,userconfig,vertrag,zustaendigkeit); TClassArray= array[Ansprechpartner..zustaendigkeit] of String; TPDInterface = class (TObject) private ClassArray: TClassArray; {{ FDatabase is the state field of the Database property. } FDatabase: TmysqlDatabase; {{ Field FPDObjects. } FPDObjects: array of TPDObject; ... function TPDInterface.GetPDObject(Index: Integer): TPDObject; var pdClass: TPDObjectClass; begin // Zur Vereinfachung: Klasse TPDAnsprechpartner finden pdClass:= TPDObjectclass(findClass('TPDAnsprechpartner')); // Erzeugen eines Objektes der gefundenen (?) Klasse // Die spezielle Klasse erfordert aber den Parameter 'Name' zur Erzeugung?! Und nicht //Database!? PDClass.Create(Database); // Demnach müsste hier stehen // PDClass.Create('MeinName'); end; Wo ist mein Fehler?! |
Re: Registrieren von Klassen
Ein Konstruktor mit diese Signatur (String als einziger Parameter) scheint in TPDObject nicht eingeführt worden zu sein und kann daher auch nicht verwendet werden (so, wie Mathoden eines Erben nicht verwendet werden können, wenn Du eine Referenz vom Typ des Vorfahren verwendest).
Dies entspricht dem Problem mit dem nicht-veränderbaren Konstruktor meines vorherigen Postings und könnte ggf mit Hilfe des Musters Abstrakte Fabrik oder bem Besucher Muster gelöst werden. Das Kernproblem: Einheitliche Verarbeitung trotz unbekannter Klasse. Verstehe ich das richtig? |
Re: Registrieren von Klassen
Hi Choose,
genau das ist das Problem! Ich will ja die speziellen Objekte erzeugen. Die Vorfahren dienen nur zur Vorhaltung allgemeiner Methoden. Allerdings weiß ich nicht wie ich das dann in eine Fabrikmethode bekomme!? Dort müsste ich dann ja nach dem übergebenen Parameter entscheiden welche Klasse zu erzeugen ist. In etwa:
Delphi-Quellcode:
Das ist ja dann nicht wirklich generisch.
function CreatePDObject(Index: Integer): TPDObject;
begin case index of 0: TPDAnsprechpartner.Create('Name'); ... end; Oder hattest Du da etwas anderes im Sinn, das mir entgangen ist?! |
Re: Registrieren von Klassen
Registriere Fabriken als Objekte (keine Klassen) innerhalb Deiner Registratur und geben ihnen bei der Ereuzgung die erforderlichen Parameter mit.
Delphi-Quellcode:
Sie selbst wissen, gemäß des Musters, wie die späteren Exemplare (zB TPDAnpsprechpartner). Es werden nun nicht länger die Klassen des gewünschten Exemplars festgehalten und zurückgegeben sondern ein geeignetes Fabrik-Objekt. Um letztlich das erforderliche Exemplar zu erzeugen, genügt ein Aufruf der Form
myConfiguration.RegisterFactory('Ansprechpartner', TAnsprechpartnerFactory.Create('Name'));
Delphi-Quellcode:
Eine Alternative wäre, den Konstruktor der gemeinsamen Oberklasse mit einem generischen Parameter (seinerseits eine abstrakte Klasse) zu versehen.
Result := myFactory.CreateInstance;
Wie erlangst Du denn überhaupt die speziellen Daten, die zur Übergabe an den Konstruktor erforderlich sind im Augenblick der Erzeugung? |
Re: Registrieren von Klassen
Hi Choose,
Zitat:
Entscheident ist, ich werde die Erzeugung der Objekte nur Vereinfachen können, indem ich der Abtrakten Fabrik den entprechenden Parameter für die Erzeugung mitgebe, wie von Dir dargetellt. Ich denke damit habe ich erst einmal zu tun und damit ist mir auch erst einmal geholfen. Solltest Du weitere Ideen, Anregungen oder Bmerkungen jeder Art haben, können wir hier gern weiterposten. Danke Dir! |
Re: Registrieren von Klassen
Hi Barnti, hi Choose :-D
kleine bemerkungen am rande:
Delphi-Quellcode:
Hier benutzt du zum definieren der array-grenzen eine range, die sowieso den gesammten bereich des enum-typs einschliesst. Dies kannst du auch so machen...
TClassIndex = (Ansprechpartner,Auftrag,auftragstatus,benutzer,bereich,beschaedigung,config,
container,dbdesigner4,dokument,foto,hafenplatz,kolli,Kunde, packliste,partie,partiestatus,partiekarte,pending,position,produktbeschreibung, produktgruppe,sql,unterpartie,userconfig,vertrag,zustaendigkeit); TClassArray= array[Ansprechpartner..zustaendigkeit] of String;
Delphi-Quellcode:
...dann müsstest du nicht immer die array-deklaration anpassen. Darüber hinnaus frag ich mich, ob dieses array überhaupt von nöten ist? Denn man kann einen enum-wert auch leicht zu einem string auflösen. zB.:
TClassArray= array[TClassIndex] of String;
Delphi-Quellcode:
Da eine metaklasse ja auch eine primitive fabrik ist, wäre das möglicherweise schon ausreichend. Hab aber dein problem auch nicht ganz kapiert. Für abstraktere lösungen bietet sich natürlich Choosens lösung an, oder eine kombination.
uses typInfo;
... function GetClassByClassIndex(const aClassIndex:TClassIndex):TPDObjectClass; var clsName:strinf; begin clsName := foramt('TPD%s',[getEnumName(TypeInfo(TClassIndex), integer(aClassIndex))]); result := findClass(clsName); end; function CreateObjectByClassIndex(const aClassIndex:TClassIndex):TPDObject; var aClass:TPDObjectClass begin aClass := GetClassByClassIndex(aClassIndex); if assigned(aClass) then result := aClass.create(<standard_params>) else result := nil; end Vielleicht nütz das dir ja was. Und ich frag mich warum du als index ansonsten einen integer benutzt, der ja alles andere als eindeutig sein kann, bzw verrutschen könnte? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:25 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