![]() |
Auf Interfaces zugreifen?
Hallo,
ich lese grad im Delphi Treff Forum herum und bin dabei auf Interfaces gestoßen. Das hat mich zu folgendem Programmentwurf inspiriert:
Delphi-Quellcode:
Wie greife ich jetzt auf das Interface zu?
unit UAppIntf;
interface uses Classes, Sysutils; type IAppInterface = Interface(IIinterface) ['{8FBE82FA-E3BA-4B8D-992D-315965BF5407}'] procedure DoSomething; End; implementation end. //Hier nun die Implementation unit UAppIntfImpl; interface uses Classes, Sysutils, Dialogs, UAppIntf; type TAppIntfImpl = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; implementation { TAppIntfImpl } procedure TAppIntfImpl.DoSomething; begin ShowMessage('the Interfaced method'); end; end. //Und hier nun will ich das Interface verwenden, ohne die Methode DoSomething noch mal //implementieren zu müssen. unit UAppIntfUser; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, UAppIntf, UAppIntfImpl; type TForm1 = class(TForm) private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} end. Wäre IAppintfImpl eine Klasse (dann TAppIntfImpl), sähe das ja so aus: var Instance: TAppIntfImpl; begin Instance := TAppIntfImpl.Create; // evtl. ...create(parameter); end. WIe aber mache ich das, wenn ich stattdessen das Interface verwenden will? |
Re: Auf Interfaces zugreifen?
Delphi-Quellcode:
var
I: IAppInterface; begin I := TAppIntfImpl.Create; // u.U. kann auch soetwas gewollt sein: I := TKlasse.Create as ISchnittstelle; end; |
Re: Auf Interfaces zugreifen?
Zitat:
Jetzt tut sich aber ein weiteres Problem auf: Wenn ich zum Instantiieren wieder, wie in der Antwort geschrieben, TAppIntfImpl.Create aufrufe, wozu dann das Interface? Dann müsste ich ja das AppInterface in der Implementationsunit instantiieren, was ich jetzt auch gemacht habe und zwar so, wie in der geänderten Unit UAppIntfImpl:
Delphi-Quellcode:
Was will ich aber nun haben?
unit UAppIntfImpl;
interface uses Classes, Sysutils, Dialogs, UAppIntf; type TAppIntfImpl = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; var //Diese Variable ist nun meine Klasseninstanz AppInterface: TAppIntfImpl; implementation { TAppIntfImpl } procedure TAppIntfImpl.DoSomething; begin ShowMessage('the Interfaced method'); end; initialization AppInterface := TAppIntfImpl.Create; finalization AppInterface.Free; end. Ich will das Interface ansprechen, als ob es die Klasse wäre. So könnte ich dann mit exakt demselben Zugriff, ohne den unten stehenden Quelltext ändern zu müssen, die Methode TAppIntfImpl.DoSomething ändern und die von jetzt an die geänderte Methode aufrufen.
Delphi-Quellcode:
Ich habe meine Unit deshalb in diese Form hier geändert:
var
I: IAppInterface; begin //heute: I := TAppIntfImpl.Create; //und morgen I := TAppIntfImpl2.Create; end;
Delphi-Quellcode:
Wenn ich das starte, erhalte ich, was ich will, die Interfaced-Methode wird aufgerufen.
unit UAppIntfUser;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, UAppIntf, StdCtrls, UAppIntfImpl; type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } FInterfaceExists: Boolean; public FInterface: IAppInterface; FInterfaced: TAppIntfImpl; { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin if FInterfaceExists then AppInterface.DoSomething; end; procedure TForm1.FormCreate(Sender: TObject); begin FInterfaceExists := true; FInterfaced := AppInterface; end; procedure TForm1.FormDestroy(Sender: TObject); begin FInterfaced.Free; end; end. Allerdings erhalte ich eine Exception mit der Meldung "ungültige Zeigeroperation". Wenn ich jedoch FInterfaced.Free im finalization Abschnitt der Unit UAppIntfImpl nicht aufrufe, kommt diese Exception nicht. Habe deshalb probeweise auch die Instantiierung im Initialization Abschnitt meiner Implementations Unit UAppIntfImpl entfernt und ich kann trotzdem auf die Klasse zugreifen. Wo gibt es weiterführende Literatur zum Thema? Nun muss ich wahrscheinlich immer den Typ der Klasse, die an das Interface angeschlossen werden soll, mitschleppen? Oder gibt es noch eine elegantere Möglichkeit. Wenn ich ein anderes Appinteface bauen will, wo zb. in der Methode FInterfaced.DoSomething der WinAmp augerufen wird und in einer anderen gleich aufgebauten Klasse der Windows Media Player. Gibt es da noch einen eleganteren Weg? . |
Re: Auf Interfaces zugreifen?
Also ich interpertiere das einfach mal...
Sagen wir mal du hast zwei Schnittstellen über die du gehen willst, einmal USB und einmal COM. Da erstellst du jeweils eine Klasse für, die das Interface implementiert und in dem Interface sind halt alle allgemeingehaltenden Methoden drin. Bsp: Das Interface:
Delphi-Quellcode:
Die USB-Schnittstelle:type ISchnittstelle = interface ( IInterface ) procedure Execute(); end; type TSchnittstelle = class ( TInterfacedObject, IInterface ) public procedure Execute(); virtual; abstract; end;
Delphi-Quellcode:
Die COM-Schnittstelle:
type
TUSBSchnittstelle = class ( TSchnittstelle ) private protected public procedure Execute(); override; end; procedure TUSBSchnittStelle.Execute(); begin // Do Something with USB end;
Delphi-Quellcode:
Und dann noch ne Factory die dir eins von beiden erstellt ( die Unterscheidung mache ich hier mit nem simplen String, geht natürlich auch anders):
type
TCOMSchnittstelle = class ( TSchnittstelle ) private protected public procedure Execute(); override; end; procedure TCOMSchnittstelle.Execute(); begin // Do Something with COM end;
Delphi-Quellcode:
So würde ich das z.b. in etwa realisieren, wenn z.b. der Benutzer die Auswahl hätte zwischen den Schnittstellen oder so.
type
TSchnittstellenFactory = class ( TObject ) private { Private-Deklarationen } protected { Protected-Deklarationen } public class function CreateSchnittstelle( sTyp: String ): ISchnittstelle; end; class function CreateSchnittstelle( sTyp: String ): ISchnittstelle; var coSchnittstelle: TSchnittstelle; begin coDependency := nil; if sTyp = "USB" then begin coDependency := TUSBSchnittstelle.Create(); end else if sTyp = "COM" then begin coDependency := TCOMSchnittstelle.Create(); end; result := coDependency; end; Natürlich nur schnell hingeklatscht...aber sollte verdeutlichen was ich meine ^^ MfG Alaitoc PS: Übernehme keine Garantie für irgendwelche Fehler, hab nu Feierabend *gg* |
Re: Auf Interfaces zugreifen?
Zitat:
Es sei denn, du schaltest mit irgendeinem Compilerschalter auf CORBA-Interfaces um, da läuft das anders. Ich gehe einfach mal von normalen COM-Interfaces aus. |
Re: Auf Interfaces zugreifen?
Hehe, Du machst mir den Eindruck als hättest Du Siebenmeilenstiefel an. Eins nach dem Anderen:
1) Hast Du mal versucht IAppInterface.Free aufzurufen? Geht nicht? Genau! Weil Free eben nicht Bestandteil der Schnittstelle ist. Bei Schnittstellen übernimmt Delphi die Referenzzählung. Wird die letzte Schnittstellenreferenz (Schnittstellenvariable) entfernt wird das Objekt automatisch freigegeben. Wer dann noch eine Objektreferenz (Objektvariable) auf das Objekt hat, hat dann "Pech gehabt", diese zeigt dann nämlich nur noch an die Stelle, wo vorher mal ein Objekt war. (Beliebte Ursache für Zugriffsverletzungen bei Neulingen auf diesem Gebiet.) Man sollte sich deshalb entscheiden, ein Objekt entweder über Schnittstellenvariablen oder über Objektvariablen anzusprechen. (Nur um es zu erwähnen: Es gibt auch Objekte die die Referenzzählung unterwandern. So eines wird aber nicht von Delphi mitgebracht.) 2) Objekte werden immer mit Create erzeugt, und immer mit Free freigegeben, unabhängig davon wie sie referenziert werden. Und noch einmal: Bei Schnittstellen entscheidet Delphi wann Free aufgerufen wird. 3) Ein wesentlicher Teil beim Programmieren besteht darin, für jeses Programmstück den richtigen Platz zu finden. Wenn man am Ende für alles einen Platz gefunden hat, und nichts doppelt oder ähnlich programmiert ist, kann man sich sicher sein, schon eine ganze Menge richtig gemacht zu haben. -- Zu Deinem Fall: Vielleicht ist möchtest Du Dein Hauprogramm mit einer Klasse parametrisieren. Schau Dir mal TClass an und denke daran den Kontruktor der Basisklasse zu überschreiben! Du kannst selbst so etwas hinzufügen:
Delphi-Quellcode:
4) Aus einer Schnittstelle kann i.d.R. das Objekt nicht wiedergewonnen werden. Dein "C := I;" wird deshalb nicht funktionieren. Außerdem: Es ist besser sich erst einmal festzulegen, Objekte entweder nur über Objektvariablen oder nur über Schnittstellenvariablen zu referenzieren. Wenigstens bis zum sicheren Umgang sollte man das wirklich beherzigen, sonst ist der Frust schnell da. Die Ursachen für Zugriffsverletzungen regelmäßig schwer zu auszumachen.
type
IKommunikation = interface end; TKommunikation = class(TInterfacedObject, IKommunikation) constructor Create; virtual; end; TKommunikationsklasse = class of TKommunikation; TUSBKommunikation = class(TKommunikation) constructor Create; override; end; TCOMKommunikation = class(TKommunikation) constructor Create; override; end; procedure THauptprogramm.MachWas(const Kommunikationsklasse: TKommunikationsklasse); var K: IKommunikation; // Schnittstellenvariable begin K := Kommunikationsklasse.Create; // usw. // nicht: K.Free; end; 5) "Was muss ich da anders machen?" Eigentlich alles. Ich hoffe Du siehst jetzt ein bisschen klarer. Wenn nicht, lass es eine Weile setzen. Spiel ein bisschen mit Klassen, Vererbung, Methodenüberschreiben und Schnittstellen in einer Konsolenanwendung (schön einfach halten). Ein bisschen im Schrittbetrieb durchgehen, bis klar ist warum das so ist. Versuche zukünftig Deine Probleme besser einzugrenzen, dann kann Dir auch besser geholfen werden. Du scheinst mir noch sehr zu schwimmen. Du bist neu hier in der DP, also auch: Ein herzliches Willkommen. :dp: |
Re: Auf Interfaces zugreifen?
Zitat:
"Why do interface implementations based on TComponent leak memory?" ![]() Denn: die Implementierung von _Release in TComponent führt kein free der Instanz aus... Cheers, |
Re: Auf Interfaces zugreifen?
Zitat:
|
Re: Auf Interfaces zugreifen?
Hier ein einfaches Beispiel, das ohne Referenzzählung auskommt und trotzdem mit Interface eine elegante Lösung bietet.
Delphi-Quellcode:
Die Funktionen in der Unit UDateioperationen können und sollen nicht wissen, wo diese später überall aufgerufen werden.
unit UProgressHandler;
interface type IProgressHandler = Interface(IIinterface) ['{...}'] procedure ProgressStart; procedure Progress(AProzent: Integer; var IsAbort: Boolean); procedure ProgressEnd; End; implementation end. unit UDateiOperationen; interface procedure KopiereDatei(const AQuelle, AZiel: string; const AProgressHandler: IProgressHandler); implementation procedure KopiereDatei(const AQuelle, AZiel: string; const AProgressHandler: IProgressHandler); begin AProgressHandler.ProgressStart; try for {... irgendeine Schleife} begin {tu irgenwas} IsAbort := False; AProgressHandler.Progress(xProzent, IsAbort); if IsAbort then Exit; end; finally AProgressHandler.ProgressEnd; end; end; end. unit UForm1; interface type TForm1 = class(TForm, IProgressHandler) FAborted: Boolean; procedure ButtonDateiKopierenClick(Sender: TObject); procedure ButtonAbortClick(Sender: TObject); {IProgressHandler} procedure ProgressStart; procedure Progress(AProzent: Integer; var IsAbort: Boolean); procedure ProgressEnd; end implementation procedure TForm1.ButtonDateiKopierenClick(Sender: TObject); begin ButtonDateiKopieren.Enabled := False; ButtonAbort.Enabled := True; FAborted := False; try KopiereDatei(EditQuelle.Text, EditZiel.Text, Self); finally ButtonDateiKopieren.Enabled := True; ButtonAbort.Enabled := False; end; end; procedure TForm1.ButtonAbortClick(Sender: TObject); begin FAborted := True; ButtonAbort.Enabled := False; end; procedure TForm1.ProgressStart; begin FProgressBar1.Visible := True; FProgressBar1.Position := 0; end; procedure TForm1.Progress(AProzent: Integer; var IsAbort: Boolean); begin FProgressBar1.Position := AProzent; IsAborted := FAborted; end; procedure TForm1.ProgressEnd; begin FProgressBar1.Visible := False; end; Trotzdem können diese über das Interface auf den Aufrufer zugreifen und sogar indirekt auf externe Ereigniss (in diesem Fall Abbruch durch den Benutzer) reagieren. |
Re: Auf Interfaces zugreifen?
Zitat:
In Delphi sind Interfaces hauptsächlich für die Verwendung zwischen verschiedenen Modulen (EXE->DLL) notwendig. Wobei man da recht schnell zu COM kommt. Bei allen anderen Interfacelösungen muss man wegen der Referenzzählung höllisch aufpassen und sollte es deswegen (meiner Meinung nach) nur sehr selten einsetzen. |
Re: Auf Interfaces zugreifen?
Zitat:
Prkatisch sind sie zum Beispiel bei der XML API, wenn man nach Belieben eine Library durch eine andere ersetzen kann, da die API einheitlich ist. Wenn ein Anbieter nette Extrafeatures hat, oder die Library besonders schlank ist, muss man nicht erst drei Tage lang refaktorisieren :) Und mit Interfaces kann man das gut von der Festlegung auf vorgegebene Klassenhierarchien trennen. Java macht das schon seit Ewigkeiten (JDBC, Mail-API, Servlet-API JMS, ...), und die Hersteller der dazu passenden Implementierungen freuen sich, dass sie eine stabile Vorgabe haben - Design by Contract sozusagen - die den berüchtigten Vendor-Lock-In verhindert. Doch bei Delphi gibt es natürlich auch Teile, die ähnlich arbeiten, dbExpress zum Beispiel, keine Frage. Wenn Delphi ein Problem mit Interfaces hat, dann eher weil der Anwender sich vertun kann bei der Mischung von Objekt- und Interfacereferenzen, oder wenn TComponent eigene Besitzerverwaltung praktiziert (und man das nicht bedenkt). Fazit: ich liebe Interfaces. Viele Grüße, Michael |
Re: Auf Interfaces zugreifen?
Zitat:
Zitat:
|
Re: Auf Interfaces zugreifen?
Hallo,
bin wieder bei den Interfaces angekommen. Hab jetzt diesen Ansatz:
Delphi-Quellcode:
unit UAppIntfFactory;
interface uses Classes, Sysutils, Contnrs, UAppIntf; var Interfaces: TInterfaceList; //In DElphi eingebaut ClassesIntf: TObjectList; //In DElphi eingebaut Interfaced: IAppInterface; procedure SetClassOf(Instance: TObject); procedure SetInterfaceOf(Name: String); function GetInterfaceOf(Name: String): IInterface; function GetClassOf(Instance: TObject): TObject; implementation uses UAppIntfImpl; procedure SetClassOf(Instance: TObject); begin if Assigned(ClassesIntf) then begin ClassesIntf.Add(Instance); end; end; procedure SetInterfaceOf(Name: String); begin if Assigned(Interfaces) then begin Interfaces.Add(Interfaced); end; end; function GetClassOf(Instance: TObject): TObject; var Index: Integer; begin if Assigned(ClassesIntf) then begin Index := 0; while Index < ClassesIntf.Count do begin { if Instance is Classesintf.Items[index] then begin Result := ClassesIntf.Items[Index]; Index := ClassesIntf.Count; end; } Inc(Index); end; end; end; function GetInterfaceOf(Name: String): IInterface; var Index: Integer; begin if Assigned(Interfaces) then begin Result := Interfaces.Items[Index]; end; end; initialization Interfaces := TInterfaceList.Create; ClassesIntf := TObjectList.Create; finalization ClassesIntf.Free; Interfaces.Free; end. //Hier die Implementation der Klassen: unit UAppIntfImpl; interface uses Classes, Sysutils, Dialogs, UAppIntf, UAppIntfFactory; type TAppIntfImpl = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; TAppIntfImpl2 = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; var InterfacedClass1: TAppIntfImpl; InterfacedClass2: TAppIntfImpl2; implementation { TAppIntfImpl } procedure TAppIntfImpl.DoSomething; begin ShowMessage('the Interfaced method von TAppIntfImpl'); end; procedure TAppIntfImpl2.DoSomething; begin ShowMessage('the Interfaced method von TAppIntfImpl2'); end; initialization //InterfacedClass := TAppIntfImpl.Create; if Assigned(Interfaces) then begin Interfaces.Add( InterfacedClass1 ); Interfaces.Add( InterfacedClass2 ); end; if Assigned(ClassesIntf) then begin ClassesIntf.Add(InterfacedClass1); ClassesIntf.Add(InterfacedClass2); end; //InterfacedClass.Free; end. //Hier kommt die Anwendung: unit UAppIntfUser; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, UAppIntf, StdCtrls, UAppIntfFactory, UAppIntfImpl; type TForm1 = class(TForm) Button1: TButton; cbxIntfChange: TComboBox; lbIntfChange: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure cbxIntfChangeCloseUp(Sender: TObject); private { Private-Deklarationen } FInterfaceExists: Boolean; public FInterface: IAppInterface; { Public-Deklarationen } FInterfaced: IAppInterface; FInterface2: TAppIntfImpl; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin if FInterfaceExists then //FInterfaced.DoSomething; FInterface2.DoSomething; end; procedure TForm1.cbxIntfChangeCloseUp(Sender: TObject); var Index: Integer; begin Index := cbxIntfChange.ItemIndex; cbxIntfChange.Text := cbxIntfChange.Items.Strings[Index]; //FInterfaced := Interfaces.Items[Index]; //------ Hier kommt eine Listen-Index-Exception, die ich mir nicht erklären kann FInterface2 := TAppIntfImpl(ClassesIntf.Items[index]); end; procedure TForm1.FormCreate(Sender: TObject); begin FInterfaceExists := true; //FInterfaced := GetInterfaceOf('Impl2'); end; end. |
Re: Auf Interfaces zugreifen?
Falls du das bis jetzt überlesen hast: NIEMALS! Objektvariablen und Interfacevariablen für ein und das selbe Objekt.
Wenn deine Faktory die Objekte erzeugen soll, die IAppInterface unterstützen, dann gehören die Units die diese Objekte deklarieren, nirgends sonst eingebunden. Die konkrete Implementation geht niemanden etwas an, maximal die Faktory kennt diese, um die Objekte zu erzeugen. Die Faktory liefert IAppInterface, also sind alle Variablen außerhalb auch IAppInterface. Hier mal eine Skizze wie eine Faktory funktionieren könnte:
Delphi-Quellcode:
Classname ist natürlich keine schöne Unterscheidung der Klassen, aber dafür kann man in TCustomAppInterface ja ein eigenes class Property / class Methode vorsehen.
unit UAppIntfDef;
type TCustomAppInterface = class(TInterfacedObject, IAppInterface) constructor Create; virtual; // virtualer Constructor für die Faktory procedure DoSomething; virtual; abstract; end; TAppInterfaceClass = class of TCustomAppInterface; implementation {********************} unit UAppIntfFactory; uses UAppIntfDef; function RegisterAppInterface(AClass: TAppInterfaceClass); procedure GetAppInterfaces(AItems: TStrings); function GetAppInterface(AName: string): IAppInterface; implementation var FClasses: TClassList; function RegisterAppInterface(AClass: TAppInterfaceClass); begin FClasses.Add(AClass); end; procedure GetAppInterfaces(AItems: TStrings); begin AItems.Clear; for i := 0 to FClasses.Count - 1 do begin AItems.Add(FClasses[i].ClassName; end; end; function GetAppInterface(AName: string): IAppInterface; begin for i := 0 to FClasses.Count - 1 do begin if FClasses[i].ClassName = AName then begin Result := TAppInterfaceClass(FClasses[i]).Create; Exit; end; end; end; {********************} unit UAppIntfImpl1; interface implementation uses UAppIntfDef, UAppIntfFactory; type TAppIntfImpl = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; procedure TAppIntfImpl.DoSomething; begin end; begin RegisterAppInterface(TAppIntfImpl); end. {********************} unit UAppIntfImpl2; interface implementation uses UAppIntfDef, UAppIntfFactory; type TAppIntfImp2 = class(TInterfacedObject, IAppInterface) constructor Create; override; procedure DoSomething; end; constructor TAppIntfImp2.Create; begin end; procedure TAppIntfImp2.DoSomething; begin end; begin RegisterAppInterface(TAppIntfImp2); end. {********************} unit UAppIntfUser; type TForm1 = class(TForm) private FInterface: IAppInterface; end; procedure TForm1.FormCreate(Sender: TObject); begin FInterface := GetAppInterface('TAppIntfImp1'); end; procedure TForm1.RadioButtonClick(Sender: TObject); var s: string; begin if Sender = RadioButton1 then s := 'TAppIntfImp1' else if Sender = RadioButton2 then s := 'TAppIntfImp2' else Exit; FInterface := GetAppInterface(s); end; procedure TForm1.ButtonClick(Sender: TObject); begin FInterface.DoSomething; end; |
Re: Auf Interfaces zugreifen?
Hallo,
die Funktion GetAppInterface sollte auch dann ein definiertes Ergebnis liefern, wenn man ihr einen unbekannten Klassennamen übergibt. Alternativ könnte sie natürlich eine Exception auslösen. Gruß Hawkeye |
Re: Auf Interfaces zugreifen?
GetAppInterface gibt hier nil zurück, wenn ein unbekannter Klassenname angegeben wird.
Im Prinzip hast du mit der Exception recht, aber das ist wie gesagt nur eine Skizze. |
Re: Auf Interfaces zugreifen?
Hallo Blup,
Zitat:
Delphi-Quellcode:
Die
function F1: IInterface;
begin Result := TInterfacedObject.Create; end; function F2: IInterface; begin end; procedure P1; var I: IInterface; begin I := F1(); if Assigned(I) then ShowMessage ('nach F1(): I <> nil'); I := F2(); if Assigned(I) then ShowMessage ('nach F2(): I <> nil'); end; ![]() Gruß Hawkeye |
Re: Auf Interfaces zugreifen?
Gut zu wissen, schlecht das der Compiler für diesen Fall keine Warnmeldung gibt.
Delphi-Quellcode:
function GetAppInterface(AName: string): IAppInterface;
begin for i := 0 to FClasses.Count - 1 do begin if FClasses[i].ClassName = AName then begin Result := TAppInterfaceClass(FClasses[i]).Create; Exit; end; end; Result := nil; end; |
Re: Auf Interfaces zugreifen?
@Hawkeye219: Das selbe Verhalten gibt es übrigens auch bei Strings und dynamischen Arrays.
[edit] ich seh grad, in der verlinkten Seite geht es um die Strings (dachte es geht da um das Interface), aber ist ja bei allem das Selbe. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:14 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