AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Deployment von Python4Delphi Programm

Ein Thema von BastiFantasti · begonnen am 9. Okt 2023 · letzter Beitrag vom 10. Okt 2023
Antwort Antwort
Seite 1 von 2  1 2      
BastiFantasti

Registriert seit: 5. Nov 2014
Ort: Baden Württemberg
133 Beiträge
 
Delphi 11 Alexandria
 
#1

Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 11:25
Hallo zusammen,

ich versuche mich gerade an der Integration von Python4Delphi.
Auf meinem Entwicklungsrechner mit installiertem Python inklusive PyEnv funktioniert das Integrieren und Ausführen wunderbar.
Auch der Einsatz von venvs funktioniert.

Jetzt wollte ich zu Testzwecken die Anwendung in einer "nackten Win10 VM" ohne installiertem Python testen.

Ich habe die benötigte Python310.dll mit ins Anwendungsverzeichnis kopiert und das TPythonEngine Objekt dynamisch erzeugt.

Code:
   
    pe1 := TPythonEngine.Create(nil);
    pe1.AutoFinalize := False;
    pe1.UseLastKnownVersion := False;
    pe1.RegVersion := '3.10';
    pe1.DllName := 'python310.dll';
    pe1.DllPath := '.\';
    pe1.IO := pyguiIO1;
    pyDVar1.ClearEngine;
    pyDVar1.Engine := pe1;
    pe1.LoadDll;
bei dem DllPath habe ich auch wahlweise das tatsächliche Anwendungsverzeichnis angegeben - mit gleichem Ergebnis.

Beim Start kommt nun die Meldung, dass die Python310.dll nicht geladen werden kann. Das Programm beendet sich dann automatisch wieder.

Dann hab ich mir gedacht, ob es noch externe Abhängigkeiten gibt...
Tatsächlich benötigt Python 3.10 unter Windows wohl die Visual C++ Runtime v14 (2015).

Seit ich die Runtime in der VM installiert habe, startet die Anwendung gar nicht mehr - es hat also scheinbar etwas bewirkt

Wie habt ihr das Deployment Problem gelöst?

Viele Grüße
Bastian
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 11:52
Nur die Python-DLL einzeln geht nicht.
Was du suchst ist das Python-Embedded.

Geh zu https://www.python.org/downloads/windows/
und besorg dir eine ZIP (Windows embeddable package 32-bit, für dein 32 Bit-Delphiprogramm)
Die Visual C++ Runtime ist dort mit enthalten.

Diese entpacken (Dateien müssen nicht im Programmverzeichnis liegen ... Unterverzeuchnis geht auch, oder daneben oder sonstwo)

Und dann im Python4Delphi die python3.dll oder z.B. explizit die python38.dll angeben und laden.

Will man zusätzlich noch PIP benutzen, dann muß man sich Dieses runterladen (als pip.pyz oder als Modul/Verzeichis innerhalb des Verzeichnisses)
sowie den PY-Script-Suchpfad im python38._pth hinzufügen, und optional auch noch noch den Suchpfad (%PATH%) auf \Scripts.
$2B or not $2B
  Mit Zitat antworten Zitat
BastiFantasti

Registriert seit: 5. Nov 2014
Ort: Baden Württemberg
133 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 12:48
Super!

Vielen Dank für die schnelle und ausführliche Antwort.
Ich werde das nachher gleich testen und mich hier wieder melden.

Viele Grüße
Bastian
  Mit Zitat antworten Zitat
BastiFantasti

Registriert seit: 5. Nov 2014
Ort: Baden Württemberg
133 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 13:33
Erstellst du das TPythonEngine Objekt als visuelle Komponente oder in einem Event beim Start der Anwendung?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#5

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 13:35
Ach ja, die "automatische" Suche, nach der aktuellen/neusten Version, funktioniert nur beim installierten Python.

Wir haben uns die Suche für das Embedded selbstgebaut. (damit wir nicht unbedingt im Programm was ändern müssen, wenn wir ein neues Python ins Verzeichnis schieben)

Also sie automatische Suche deaktiviert und dann die Python-DLL mit absolutem Pfad beim Python4Delphi angeben.
Aber zumindestens kann man statt python310.dll auch einfach python3.dll benutzen, was eine Umlautung zur aktuellen python3*.dll darstellt (jeweils auf die aktuelle Version der ZIP bezogen)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#6

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 13:53
Ich bin aktuell dabei mit PIP zu spielen ... funktioniert eigentlich gut,
aber neue Scripte mit Modulen/Imports, welche eigene .PYD und .DLL laden, bereiten Probleme.

Zuerst visuell rumgespielt
und dann alles in eine Komponente veeschoben. (inkl. Variablen von Inhalten aus der aktuellen Form, sowie Durchreichen von Delphi-Funktionen ins Python, bevor das Script ausgeführt wird)
Im Prinzip reicht so minimal eine Funktion, welcher ich die akktuelle Form und das Python-Script als String übergebe und einen String zurückbekomme.

Und, damit zwischen den Scripten keine Dinge durchwandern, hatten wir uns damals entschlossen das Python nach jeder Ausführung zu beenden und die DLL zu entladen,
damit keine Variablen und geladenen/benutzen Klassen von einer Script-Ausführung ins nächste Script kommen.
Wir hatten es nicht hinbekommen ein Reset zu implementieren und das war die schnellste Lösung. (auch das Laden/Entladen der zwei DLLs (python38.dll und vcruntime140.dll geht enorm ausreichend schnell)
PS: 3.8, da wir mit unseren jahrzehntealten Sctipten (damals noch über die Python.exe des Embedded-Python) in der 3.10 Probleme haben. (und keine Lust/Zeit ALLE Scripte umzubauen und zu prüfen, auch fremde Scripte bei vielen unserer Kunden)

Das ging bisher gut, aber Script-Entwickler und auch die Python-Entwickler sind Schweine, welche nicht wirklich an eine Embedded-Nutzung dachten .... also Vieles einfach garnicht wieder freigeben. (das Beenden der Python-EXE erledigt das ja normalerweise, aber siehe meine Signatur )

Wie ich geladene DLL/PYD ordentlich entladen kann, weiß ich inzwischen (hat 'ne Woche Arbeit und zu viele graue Haare gekostet, aber Windows sagt mir nun endlich, welche DLLs geladen wurden, in welcher Reihenfolge und warum, also ob z.B. durch manuelles LoadLibrary, eine statische Verlinkung, sowie DelayedLoading und Anderes).
Aber z.B. beim PySide bleibt dennoch ein Speicherleck von 9-11 MB und selber vorher (war aber grade erst aufgefallen) war schon ein 3-4 MB Leck vorhanden gewesen.
(wir wollten nun eigentlich Python mehr verwenden, aber wenn nach 100 Ausführungen plötzlich 300 bis 1000 MB RAM verschwinden, ist das in Win32 schon bissl blöd, selbst mit der 4GB-Erweiterung)
$2B or not $2B
  Mit Zitat antworten Zitat
BastiFantasti

Registriert seit: 5. Nov 2014
Ort: Baden Württemberg
133 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 13:59
Ja das mit dem Speicherleck klingt in der Tat problematisch ...

Bei Pip usw bin ich noch nicht. Noch kämpfe ich mit dem "Hello World"

Ich bin jetzt auch einen Schritt weiter.
Ich habe das Paket heruntergeladen und in ein Unterverzeichnis gepackt.
Scheinbar kann die DLL jetzt initial geladen werden.
Nun wirft er aber den nächsten Fehler: "Could not map symbol Py_DebugFlag"
obwohl ich eigentlich keine Flags in dem Konstruktur bzw. der Initialisierung der PythonEngine gesetzt habe.
  Mit Zitat antworten Zitat
BastiFantasti

Registriert seit: 5. Nov 2014
Ort: Baden Württemberg
133 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 14:41
benötigt man für diesen Einsatzzweck dann auch noch ein TPyEmbeddedEnvironment Objekt?
Oder reicht es aus, das TPythonEngine Objekt entsprechend zu konfigurieren?
  Mit Zitat antworten Zitat
BastiFantasti

Registriert seit: 5. Nov 2014
Ort: Baden Württemberg
133 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 16:17
Jetzt habe ich es tatsächlich hinbekommen, dass er das entsprechende embedded python lädt.

Verwendest du immer das Embedded Python oder wechselst du auch zum "normal installierten" Python / oder zu einem venv?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#10

AW: Deployment von Python4Delphi Programm

  Alt 9. Okt 2023, 16:26
Nee, wir nutzen immer das selbstmitgebrachte Python.

Da wir nicht kontrollieren können ob und welche Python-Version auf Kundensystemen installiert sind,
haben wir so unser eigenes Python, mit welchem wir bei uns auch Testen konnten.
Wäre es z.B. als 64 Bit installiert, dann kann es im Delphi unter 32 Bit nicht benutzt werden und es knallt.

Sowie eben (noch) die etwas ältere Version, welche aber noch mit den meisten Scripten kompatibel ist. (sie Scripte sind bei uns in der Datenbank gespeichert, mit einer Synchronisation von/zu uns)



Ansonsten nutzen wir einen Fork vom https://github.com/pyscripter/python4delphi
da sind die Änderungen für "unsere" automatische Versions-Suche im Embedded-Verzeichnis.
Und wir könnten gezielt die Updates übernehmen (oder auch nicht)

PS: Da der Entwickler bösartig AnsiString für seine Parameter benutzt hat, die das Python aber eigentlich mit UTF-8 nutzt,
mußte ich da bissl rumtricksen, damit Unicode/Umlaute nicht kaputt gehn.

Auszug:
Delphi-Quellcode:
type
  TXXXXXXPython = class(TObject)
  private
    FPythonEngine: TPythonEngine;
    FPythonInputOutput: TPythonInputOutput;
    FPythonModule: TPythonModule;
    FPythonDelphiWrapper: TPyDelphiWrapper;
    FPythonDelphiVar: TPythonDelphiVar;
    FPythonOutput: RawByteString;
    FInitScript: String;
    FUseInstalledPython: Boolean;
    FDLLFilename: string; //leer sucht installiertes Python (Achtung: muß 32 Bit sein, egal ob Installiert oder Embedded)
    //
    function GetPythonOutput: string;
    function GetParamCount(Args: PPyObject): Integer;
    function GetParam(Args: PPyObject; Index: Integer; IsOptional: Boolean=False): Variant;
    function CreateResult(Value: Variant): PPyObject;
    function GetVariable(Name: string): Variant; // [DCC Hinweis] H2219 Das private-Symbol 'GetVariable' wurde deklariert, aber nie verwendet -> aktuell auskommentiert, siehe TXXXXXXPython.Engine_Initialize
    procedure SetVariable(Name: string; Value: Variant);
    //
    procedure InputOutputSendData(Sender: TObject; const Data: AnsiString);
    procedure ExecuteInitScript;

    procedure FindPythonDLL;

  public class var
    _GetValueFromEdit: function(FrameOrForm: TComponent; EditName: string; UseParamsIfEmpty: Boolean=False): Variant; // XXXXXXUtils.GetValueFromEdit für Py_GetValueFromEdit
    _FillQueryParamsWithFormValues: procedure(Query: TCimQuery2; _Self: TComponent; DebugInfo: string; AddPercent: Boolean=False; pOverride: Boolean=False); // XXXXXXUtils._FillQueryParamsWithFormValues für Py_DBExecute/Py_DBSelect
  public
    RuntimeForm: TForm; // TfrmToDesign
    OwnerModul: TForm; // TModulForm usw. (für GetValueFromEdit und FillQueryParamsWithFormValues)

    constructor Create;
    destructor Destroy; override;

    procedure Engine_Initialize;
    procedure Engine_Finalize(doLog: Boolean = True);
    //
    function CheckExecute(Script: string; RaiseError: Boolean = True): Boolean;
    function Execute (Script: string): string;
    //
    function CheckEval (Script: string; RaiseError: Boolean = True): Boolean;
    function Eval (Script: string): Variant;
    //
    property InitScript: string read FInitScript write FInitScript;
    property Output: string read GetPythonOutput;

    property UseInstalledPython: Boolean read FUseInstalledPython write FUseInstalledPython;
    property Engine: TPythonEngine read FPythonEngine;

  private
    // Beschreibng der Parameter
    // siehe in Implementation als Kommentar an den Funktionen
    // bzw. siehe TXXXXXXPython.Engine_Initialize als Kommentar an Python (TODO: schauen wie das ins CodeComplete des SynEdit gelangt)

    function Method_Test (PSelf, Args: PPyObject): PPyObject; cdecl;

    function Py_GetValueFromEdit(PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_GetSetting (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_SetSetting (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_GetBoolSetting (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_SetBoolSetting (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_GetIntSetting (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_SetIntSetting (PSelf, Args: PPyObject): PPyObject; cdecl;

    function Py_DBExecute (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_DBSelect (PSelf, Args: PPyObject): PPyObject; cdecl;

    function Py_DMSFileByDokID (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_DMSFileByRecNo (PSelf, Args: PPyObject): PPyObject; cdecl;
    function Py_DMSFileImport (PSelf, Args: PPyObject): PPyObject; cdecl;
  end;

function EscapePythonString(S: string): string;

procedure TXXXXXXPython.Engine_Initialize;
begin
  Engine_Finalize(False);

  FPythonOutput := '';

  FPythonInputOutput := TPythonInputOutput.Create(nil);
  FPythonInputOutput.UnicodeIO := False;
  FPythonInputOutput.OnSendData := InputOutputSendData;

  // Non-RawOutput könnte zu Problemen führen,
  // da 'unvollständige' Implementierung
  FPythonInputOutput.RawOutput := True;
  FPythonInputOutput.DelayWrites := False;

  //https://github.com/pyscripter/python4delphi/wiki/FindingPython
  FPythonEngine := TPythonEngine.Create(nil);
  FPythonEngine.AutoLoad := False;
  FPythonEngine.FatalAbort := False;
  FPythonEngine.FatalMsgDlg := False;

  FPythonEngine.UseLastKnownVersion := UseInstalledPython;
  //
  if FDLLFilename <> 'then begin
    FPythonEngine.DllName := ExtractFileName(FDLLFilename);
    FPythonEngine.DllPath := ExtractFilePath(FDLLFilename);
    FPythonEngine.SetPythonHome(FPythonEngine.DllPath);
    //FPythonEngine.RegVersion := '3.9';
  end;
  //
  FPythonEngine.IO := FPythonInputOutput;

  FPythonModule := TPythonModule.Create(nil);
  FPythonModule.Engine := FPythonEngine;
  FPythonModule.ModuleName := 'XXXXXX';
  FPythonModule.DocString.Text := 'our XXXXXX-Modul: Functions and Variables inside XXXXXX-Client';

  FPythonDelphiWrapper := TPyDelphiWrapper.Create(nil);
  FPythonDelphiWrapper.Engine := FPythonEngine;
  FPythonDelphiWrapper.Module := FPythonModule;

  // TODO: Ich weiß nicht warum, aber bei André funktioniert es, und bei mir nicht,
  // weder im Embedded (DLLName) noch im installierten Python (UseLastKnownVersion).
  // -> 'VariableXyz' object has no attribute 'Value'
  // DemoCode im Scipt-Memo auskommentert (#)

  //erledigt! gefixt: https://en.delphipraxis.net/topic/4323-pythondelphivar-thows-attributeerror-that-object-has-no-attribute-value-python-391-32bit/
  FPythonDelphiVar := TPythonDelphiVar.Create(nil);
  FPythonDelphiVar.Engine := FPythonEngine;
  FPythonDelphiVar.VarName := 'VariableXyz';
  //FPythonDelphiVar.Module := '__main__'; // Python-MainModule: Variable global "VariableXyz.Value" oder als "__main__.VariableXyz.Value"
 { FPythonDelphiVar.OnChange        := PythonDelphiVarOnChange;
  FPythonDelphiVar.OnGetData        := PythonDelphiVarOnGetData;
  FPythonDelphiVar.OnSetData        := PythonDelphiVarOnSetData; }


  FPythonEngine.LoadDll;
  if not(FPythonEngine.IsHandleValid) then
    raise Exception.Create('PythonEngine.LoadDll: ' + SysErrorMessage(GetLastError));

  if not(FPythonEngine.Initialized) then begin
    TPythonEngineAccess(FPythonEngine).Initialize;
    if not(FPythonEngine.Initialized) then
      raise Exception.Create('PythonEngine.Initialize: ' + SysErrorMessage(GetLastError));
  end;

  {$REGION 'PythonModule.OnInitialization'}

  FPythonModule.AddDelphiMethod('Method_Test', Method_Test, 'Method_Test(a, b)');

  FPythonModule.AddDelphiMethod('GetValueFromEdit', Py_GetValueFromEdit, 'GetValueFromEdit(EditName): Variant');
//FPythonModule.AddDelphiMethod('GetControlValue', Py_GetControlValue, 'GetControlValue(EditName): Variant');
//FPythonModule.AddDelphiMethod('SetControlValue', Py_SetControlValue, 'SetControlValue(EditName, Value)');

  FPythonModule.AddDelphiMethod('GetSetting', Py_GetSetting, 'GetSetting(Name): String');
  FPythonModule.AddDelphiMethod('SetSetting', Py_SetSetting, 'SetSetting(Name, StrValue)');
  FPythonModule.AddDelphiMethod('GetBoolSetting', Py_GetBoolSetting, 'GetBoolSetting(Name): Boolean');
  FPythonModule.AddDelphiMethod('SetBoolSetting', Py_SetBoolSetting, 'SetBoolSetting(Name, BoolValue)');
  FPythonModule.AddDelphiMethod('GetIntSetting', Py_GetIntSetting, 'GetIntSetting(Name): Integer');
  FPythonModule.AddDelphiMethod('SetIntSetting', Py_SetIntSetting, 'SetIntSetting(Name, IntValue)');

  FPythonModule.AddDelphiMethod('DBExecute', Py_DBExecute, 'DBExecute(InsertOrUpdateStatement)');
  FPythonModule.AddDelphiMethod('DBSelect', Py_DBSelect, 'DBSelect(SelectStatement): FirstStringBooleanOrInteger');

  FPythonModule.AddDelphiMethod('DMSFileByDokID', Py_DMSFileByDokID, 'DMSFileByDokID(pd_id): String');
  FPythonModule.AddDelphiMethod('DMSFileByRecNo', Py_DMSFileByRecNo, 'DMSFileByRecNo(TableName, RecId, [DokType], [OnlyStandard]): String');
  FPythonModule.AddDelphiMethod('DMSFileImport', Py_DMSFileImport, 'DMSFileImport(FileName, TableName, DBRID, [DokType], [DokIdent], [Caption]): Integer');

  FPythonModule.Initialize;
  FPythonDelphiWrapper.Initialize;

  if Assigned(FPythonDelphiVar) then
    FPythonDelphiVar.Initialize;

  //FPythonDelphiVar.Value := 20; //kann man vom Code setzen

  FPythonModule.SetVarFromVariant('Var123', 123456);
  SetVariable('Var456', 987654);

  //v := GetVariable('Var456'); //es geht
  //v := GetVariable('VariableXyz'); //es geht nicht

  FPythonEngine.PyObject_SetAttrString(FPythonEngine.GetMainModule, 'Var456', FPythonEngine.VariantAsPyObject(987654));

  {$ENDREGION}

  //FPythonEngine.ExecString('weiterer Python-Code für Initialisierung'); // Standard-Module importieren, Variablen setzen, ...
  //DoLogEvent('Python-Init: %dms', [Integer(TThread.GetTickCount - PythonRuntime)]);
end;

function TXXXXXXPython.Execute(Script: string): string;
var
  Temp: RawByteString;
begin
  Engine_Initialize;
  try
    ExecuteInitScript;
    Temp := UTF8Encode(Script);
    SetCodePage(Temp, CP_ACP, False); // damit Delphi das UTF-8 nicht nach ANSI konvertiert, da die Parameter als ANSI deklariert wurden
    FPythonEngine.ExecString(AnsiString(Temp)); //FPythonEngine.ExecString(FPythonEngine.EncodeString(Script)); -> EncodeString ist defekt
    Result := Self.Output;
  finally
    Engine_Finalize;
  end;
end;
Delphi-Quellcode:
  Python := TProdatPython.Create;
  try
    //if not Python.CheckExecute(Script, False) then raise ....
    edPythonResult.Text := Python.Execute(Script);
  finally
    Python.Free;
  end;
Delphi-Quellcode:
  TDM1.ScreenCursorSwitchToHoureGlass(True);
  Python := TXXXXXPython.Create;
  try
    {$IFDEF EUREKALOG}  // Eurekalog deaktiveren > Grund: 5 Fehler und das war es
    ELActive := IsEurekaLogActive;
    SetEurekaLogState(False);
    {$ENDIF}

    Python.RuntimeForm := nil;
    Python.OwnerModul := FindModule(TModulForm, True);
    ...

    if Python.CheckExecute(Script, False) then
      try
        {Res :=} Python.Execute(Script);
      finally
        // auch bei einem Fehler den bereits vorhandenen Output anzeigen (inkl. Fehlerposition, Stacktrace und Fehlermeldung)
        edPythonResult.Text := TrimRight(TRegEx.Replace(Python.Output, '^( *\r?\n)*', '', [roSingleLine])); // das Resultat des Scriptes von StdOut
      end
    else
      edPythonResult.Text := Format('Error: Skript kann nicht ausgeführt werden%s%s', [sLineBreak + sLineBreak, Python.Output]);
  finally
    {$IFDEF EUREKALOG}
    SetEurekaLogState(ELActive);
    {$ENDIF}
    Python.Free;
    TDM1.ScreenCursorSwitchToHoureGlass(False);
  end;
$2B or not $2B

Geändert von himitsu ( 9. Okt 2023 um 16:44 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:32 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