![]() |
Externes Programm ausführen
Hallo Delphifreunde/innen,
ich führe Exiftool von Phil Harvey aus, um die vollständigen Metadaten eines Bildes zu erhalten. Exiftool ist ein Programm ohne Oberfläche. Ich starte Exiftool aus meiner Anwendung, Exiftool legt eine temporäre Datei an, die ich dann mit meiner Anwendung einlese und anzeige. Das hat bis jetzt gut funktioniert, seit dem letzten Windows-Update nicht mehr. Unter Vista läuft es immer noch! Zum Ausführen von Exiftool benutze ich diese Routine, nicht von mir wahrscheinlich hier aus dem Forum.
Delphi-Quellcode:
Unter Windows 10 nach dem Update liefert sie false zurück.. CreateProcess wird ausgeführt, denn sonst gäbe es eine Fehlermeldung.
function ExecAndWait(const CommandLine, Parameter: string; SWModus: Word=SW_HIDE) : Boolean;
var StartupInfo: Windows.TStartupInfo; // start-up info passed to process ProcessInfo: Windows.TProcessInformation; // info about the process ProcessExitCode: Windows.DWord; // process's exit code begin // Set default error result Result := False; // Initialise startup info structure to 0, and record length FillChar(StartupInfo, SizeOf(StartupInfo), 0); StartupInfo.cb := SizeOf(StartupInfo); StartupInfo.dwFlags := STARTF_USESHOWWINDOW; StartupInfo.wShowWindow:=SWModus; // Execute application commandline if Windows.CreateProcess(nil, PChar(CommandLine), nil, nil, False, 0, nil, PChar(Parameter), StartupInfo, ProcessInfo) then begin try // Now wait for application to complete if Windows.WaitForSingleObject(ProcessInfo.hProcess, INFINITE) = WAIT_OBJECT_0 then // It's completed - get its exit code if Windows.GetExitCodeProcess(ProcessInfo.hProcess, ProcessExitCode) then // Check exit code is zero => successful completion if ProcessExitCode = 0 then Result := True finally // Tidy up Windows.CloseHandle(ProcessInfo.hProcess); Windows.CloseHandle(ProcessInfo.hThread); end end else Showmessage(Format('Fehler:%d - %s!',[GetLastError,SysErrorMessage(GetLastError)])) end; {ExecAndWait} Ich weise darauf hin, dass ich ExecAndWait oft benutze auch mit Exiftool, nur hier geht's nicht. Was kann Microsoft geändert haben? Hat jemand eine Idee, woran das liegen kann. Gruß Willie. |
AW: Externes Programm ausführen
Du hast doch einen Debugger. False kommt nur zurück wenn entweder WaitForSingleObject oder GetExitCodeProcess fehlschlägt oder der ExitCode ungleich Null ist.
Die ganzen WinApi-Funktionen die einen Boolean zurückgeben würde ich immer mit
Delphi-Quellcode:
prüfen. Deine Methode wirft dann direkt die passene
Win32Check(..)
Delphi-Quellcode:
-Exception, da musst du nichts mehr mit
EOSError
Delphi-Quellcode:
usw. herauspflücken.
GetLastError()
|
AW: Externes Programm ausführen
So, wie ich das sehe, ist das Verhalten unter Vista falsch.
GetExitCodeProcess ist ungleich 0, wenn alles korrekt gelaufen ist. Du prüfst aber auf gleich 0 ![]() Zitat:
|
AW: Externes Programm ausführen
Nein, er prüft ProcessExitCode gegen 0, nicht den Rückgabewert der Funktion.
|
AW: Externes Programm ausführen
Ja, Sorry.
Ich bin auf den Klassiker reingefallen. :roll: Habe mal meine alten Sourcen durchgesehen. Der Status könnte an der Stelle noch STILL_ACTIVE sein, auch wenn der Prozess eigentlich beendet ist. Das ist dann ungleich 0. Deswegen sollte man auch WaitForSingleObject verwendet, wie es hier schon im Source steht. Nutzt man nur GetExitCodeProcess in einer Schleife, kann das eine Endlos-Schleife werden. Zumindest habe ich das bei mir so notiert. |
AW: Externes Programm ausführen
Was gibt GetExitCodeProcess denn zurück? False? Oder ist ProcessExitCode ungleich 0? Das solltest du zunächst einmal im Debugger prüfen wie schon erwähnt.
Und wenn du ohnehin eine Meldung bei einem Fehlschlag anzeigst, könntest du das dort auch machen. Ich würde allerdings eher Exceptions verwenden, denn mit der Meldung ist der Fehler ja nicht unbedingt behandelt. |
AW: Externes Programm ausführen
Antwort an euch alle:
ich hab's ausprobiert, auch auf einem Laptop mit Windows 10 vor dem letzen Update läuft es, wie gewünscht! Ich werde euren Ratschlägen folgen und mich dann wieder melden. Willie. |
AW: Externes Programm ausführen
Hallo Günther,
ich habe ExecAndWait debuggt. Es wird vollständig durchlaufen, Rückgabewert immer true. Ich habe festgestellt, dass unter Windows 10 nach dem Update die temporäre Datei, die Exiftool mit den Metadaten anlegen soll, nicht erzeugt! Ich benutze die neuste Version Exiftool. Was hat Microsoft da gedreht? Eure Expertise ist gefragt, danke. Willie. |
AW: Externes Programm ausführen
Hallo Willie,
wo soll die temporäre Datei denn erstellt werden? Eventuell gibt es hier ein Berechtigungsproblem... Zitat:
|
AW: Externes Programm ausführen
Ich würd' ja mal den Wert von ProcessExitCode abfragen. <> 0 heißt Fehler. Der entsprechende Wert gibt eventuell Auskunft darüber, was beim Exiftool schiefgegangen ist, den Fehler würd' ich dann mal beseitigen.
Eventuell mal CommandLine und Parameter ausgeben und auf der Kommandozeile nachschauen, ob dort bereits eine Fehlermeldung erscheint? Wenn es dort bereits nicht funktioniert, den Fehler beheben und anschließend dann mit dem eigenen Programm das Zusammenspiel erneut testen. |
AW: Externes Programm ausführen
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo,
in dem Temp-Ordner. Bei mir c:\users\nutzername\appdata\local\temp (ermittelt durch Windows-Funktion). Auf dem Desktop-PC: Windows 10 1709 Built 16299.98 von letzter Woche. Hier gehsts nicht Laptop: Windows 10 1709 Built 15062.726. Hier gehts. Ich hab's gerade nochmal auf dem Laptop versucht, die Datei hänge ich an, ebenso einen Auszug aus der Doku von Phil Harvey zu Exiftool. Ich werde ein Testprogramm entwickeln und sehen, ob ich dann heraus finde, warum die Datei nicht gespeichert wird. Willie. |
AW: Externes Programm ausführen
Hallo,
ist es der gleiche Benutzername? |
AW: Externes Programm ausführen
Ja!
Ich habe Exiftool in der "Eingabeaufforderung" ausgeführt und die Datei in den TEMP-Ordner ablegen wollen, ging nicht "Zugriff verweigert". Willie. |
AW: Externes Programm ausführen
Sicher, dass du TEMP eingegeben hast und nicht %TEMP% ?
Ist meiner Meinung nach aber kein Codeproblem sondern nur ein verkorkstes Windows 10. |
AW: Externes Programm ausführen
Da könntest du recht haben. Es sieht wohl so aus, dass Exiftool die Datei nicht in TEMP schreiben kann.
Morgen werde ich es nochmal versuchen. Da fällt mir gerade ein, könnte der Virenwächter dazwischen funken? Schließlich wird eine Datei erzeugt und abgelegt. Willie. |
AW: Externes Programm ausführen
Liste der Anhänge anzeigen (Anzahl: 1)
EXIF Tool ist auch für mich ein extrem interessantes Programm. Nur der Weg über diese temporären Dateien stört mich enorm.
Geht eigentlich nicht der Weg über eine pipe? Auf Harveys Seite gibt es einen Link zu ![]()
Delphi-Quellcode:
macht. Siehe vielleicht auch
CreatePipe
![]() PS: Bin ja doof, ich sehe eben, die Umsetzung schlummert schon längst auf meiner Festplatte... Hier ist die Unit:
Delphi-Quellcode:
Aufruf:
unit ExifTool;
interface uses Classes; var ETout, ETerr: TStringList; //data from ExifTool will be here function ExecuteET(const ETcmd,WorkDir: string): Boolean; implementation uses Windows; function ExecuteET(const ETcmd,WorkDir: string): Boolean; const szBuffer=255; var StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; PWorkDir: PChar; SecurityAttr: TSecurityAttributes; PipeOutputRead: THandle; PipeOutputWrite: THandle; PipeErrorsRead: THandle; PipeErrorsWrite: THandle; Succeed: Boolean; Buffer: array [0..szBuffer] of Char; BytesRead: DWORD; Stream: TMemoryStream; begin //=== Usual steps to initialize data for CreateProcess: FillChar(Buffer,SizeOf(Buffer),0); FillChar(ProcessInfo, SizeOf(TProcessInformation), 0); FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0); SecurityAttr.nLength := SizeOf(SecurityAttr); SecurityAttr.bInheritHandle := true; SecurityAttr.lpSecurityDescriptor := nil; CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0); CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0); FillChar(StartupInfo, SizeOf(TStartupInfo), 0); StartupInfo.cb:=SizeOf(StartupInfo); with StartupInfo do begin hStdInput:=0; hStdOutput:=PipeOutputWrite; hStdError:=PipeErrorsWrite; wShowWindow:=SW_HIDE; dwFlags:=STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; end; if WorkDir='' then PWorkDir:=nil else PWorkDir:=PChar(WorkDir); ETout.Clear; ETerr.Clear; //=== Here is where ExifTool is called: if CreateProcess(nil, PChar(ETcmd), nil, nil, true, CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, PWorkDir, StartupInfo, ProcessInfo) then begin //=ExifTool started successfully: result:=true; CloseHandle(PipeOutputWrite); CloseHandle(PipeErrorsWrite); end else begin //=ExifTool not started (because, i.e. not found): result:=false; CloseHandle(PipeOutputRead); CloseHandle(PipeOutputWrite); CloseHandle(PipeErrorsRead); CloseHandle(PipeErrorsWrite); end; if result then begin //= Get output written by ExifTool(tag names/values): Stream:=TMemoryStream.Create; try repeat succeed:=ReadFile(PipeOutputRead,Buffer,szBuffer,BytesRead,nil); if not succeed then break; Stream.Write(Buffer,BytesRead) until (BytesRead=0); Stream.Position:=0; ETout.LoadFromStream(Stream); finally Stream.Free; end; CloseHandle(PipeOutputRead); //= Get errors written by ExifTool (if any): Stream:=TMemoryStream.Create; try repeat succeed:=ReadFile(PipeErrorsRead,Buffer,szBuffer,BytesRead,nil); if not succeed then break; Stream.Write(Buffer,BytesRead); until (BytesRead=0); Stream.Position:=0; ETerr.LoadFromStream(Stream); finally Stream.Free; end; CloseHandle(PipeErrorsRead); WaitForSingleObject(ProcessInfo.hProcess,5000); //=5sec CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); end; end; initialization begin ETout:=TStringList.Create; ETerr:=TStringList.Create; end; finalization begin ETerr.Free; ETout.Free; end; end.
Delphi-Quellcode:
Das Ergebnis ist dann in ETout
procedure FühreTestCodeAus;
var ETool,ETCmd,Datname:string; begin ETool := 'C:\EXIFTool\exiftool.exe '; ETCmd := ' -k -a -u -g1 -lang de '; Datname := '"C:\Temp\Test\01-Testdatei.JPG"'; ExecuteET(ETool + ETCmd + Datname,''); end; |
AW: Externes Programm ausführen
Handelt es sich bei dem Inhalt der Temp-Datei um die Konsolenausgabe des ExifTools, die per > in 'ne Datei umgeleitet wurde?
Dann mal hier im Forum nach "Process Pipe" suchen. Da müsste was brauchbares zu finden sein, per Pipe bekommt man die Konsolenausgabe des ExifTools dann direkt ins Programm geliefert. |
AW: Externes Programm ausführen
Zitat:
|
AW: Externes Programm ausführen
Ok. Und wenn man den Schalter weglässt, dann erfolgt die Ausgabe auf die Konsole und kann dann (ohne Datei) per Pipe ins Programm übernommen werden.
Er wäre (denk ich) mal 'nen Versuch wert, ob man so die Kommunikation zwischen Programm und ExifTool vereinfachen kann und man muss sich dann nicht darum kümmern, ob man für (nur temporär benötigte) Dateien alle erforderlichen Rechte hat. |
AW: Externes Programm ausführen
Vielleicht hast du
![]() |
AW: Externes Programm ausführen
Ja, die Änderung von 23:21 Uhr, hab' ich irgendwie nicht mitbekommen, aber genau das meinte ich. Ist wohl schon zu spät :-(
|
AW: Externes Programm ausführen
In solch einem Fall ist es am einfachsten den Process Monitor zu benutzen, um damit einfach festzustellen was eigentlich mit der temporären Datei schiefgeht. Dort siehst du ganz genau, ob die Datei im falschen Ordner erstellt werden soll oder was sonst das Problem ist.
![]() Bei Filter setzt du process name is deine.exe, das war es. |
AW: Externes Programm ausführen
Ich werde alles ausprobieren, ich bin sehr interessiert. Exiftool ist meiner Meinung nach das beste Programm für Metadaten von Bildern, besonders zum Schreiben von Daten z.B des Orientation-Tag, damit das Bild richtig gedreht wird.
Danke, ich melde mich... Willie. |
AW: Externes Programm ausführen
Hallo,
ich weiß jetzt, wie Exiftool in der Eingabeaufforderung eine externe Textdatei mit den Metadaten anlegt. Es geht so: In der Eingabeauff.: 1. Beispiel exiftool Korfu.jpg >"%temp%"\Bild.txt piped Bild.txt in Temp-Ordner des BS. 2. Beispiel exiftool Korfu.jpg -w! .txt legt Korfu.txt im gleichen Ordner wie das Bild ab. 3. Beispiel exiftool Korfu.jpg -w! %dc:\data\%f.txt legt Korfu.txt im Ordner Data ab, falls nicht vorhanden, wird er angelegt. 4. Beispiel exiftool Korfu.jpg -w! %d"%temp%"\%f.txt legt Korfu.txt im Temp-Ordner des BS ab. Hier klappt es. Ich habe das Brett an der dünnsten Stelle gebohr, benutze ShellExecute mit dem Parameter Korfu.jpg -w! .txt wird Korfu.txt im gleichen Ordner wie das Bild angelegt. Wenn ich einen anderen Pfad wähle, geht es nicht. Jaenicke, als Amateur bin ich mit ProcessMon überfordert. Die Help.chm funktioniert nicht! Kannst du mir bitte genauer beschreiben, wie ich vorgehen mus. Ich darf nochmal daraufweisen, es hat 5 Jahre lang funktioniert. Benmik, es sieht ja so aus, als ob der Umweg über eine externe Datei nicht notwendig ist. Ich hatte Piping in der Eingeauff. erfolgreich getestet aber den Weg über TMemoryStream kenne ich nicht. Es klappt, ich werde ihn in mein Programm einbauen. Danke und Gruß Willie. |
AW: Externes Programm ausführen
Ich würde mich freuen, wenn du später hier mal deine Erfahrungen mitteilen würdest, insbesondere, welche Kommandos und Schalter du eingesetzt und getestet hast.
|
AW: Externes Programm ausführen
Hallo Benmik,
das will gerne tun. Ich habe -lang de ausprobiert. Hier gibt es Probleme mit dem Zeichensatz. Die deutschen Umlaute werden falsch dargestellt. Ich hab's mit OEMToChar und OEMConvert versucht, geht aber nicht. So geht es nicht: Memo1.Lines.OEMConvert:=true; CharToOEM(PWideChar(ETout.Text),PAnsiChar(Memo1.Li nes.Text)); Der Rückgabewert ist false Ich sehe, über dieses Thema gibt es hier schon Beiträge, sie helfen mir aber nicht weiter... Ich sehe, du hast auch die Starter Edition, es ist ein Elend, dass sich Variablen nicht im Schwebefenster direkt anzeigen lassen! Willie1. |
AW: Externes Programm ausführen
Memo1.Lines.Text ist und bleibt immer ein UnicodeString und das kannst/darfst du niemals nach PAnsiChar konvertieren.
Aber natürlich ist dir schon lange die Kompilerwarnung an dieser Stelle aufgefallen. OEMConvert kannte ich noch nicht, aber wenn ich mir so die Hilfe durchlese, dann würde ich sagen, dass es sich ausschließlich auf das UserInterface, also um die Eingabe des Benutzers handelt und sich Programmintern auf nichts auswirkt. CharToOEM will auch auf der rechten Seite garantiert eine Variable haben, mit der selben Größe (Length) wie Links, und du gibst da den Zeiger auf die temporäre Ausgabe eines Property rein. |
AW: Externes Programm ausführen
Schau bitte mal, ob Du (sinngemäß) hiermit weiter kommst, es stammt aus 'ner alten Delphi 7-Komponente zum Aufruf von Konsolenprogrammen:
Delphi-Quellcode:
function OEM2Ansi(OEMString: string): string; begin OEMString := OEMString + #0; OemToChar(PChar(OEMString), @OEMString[1]); Delete(OEMString, Length(OEMString), 1); Result := OEMString; end; ... repeat succeed:=ReadFile(PipeOutputRead,Buffer,szBuffer,BytesRead,nil); if not succeed then break; // Hier die Funktion einfügen, vor dem Schreiben der Ausgabe in den Stream. OemToAnsi(Buffer^,Buffer^); Stream.Write(Buffer,BytesRead) until (BytesRead=0); ... |
AW: Externes Programm ausführen
Zitat:
OEMString hätte schon immer ein AnsiString sein müssen und das knallt nun bei der Unicode-Umstellung seit Delphi 2009. PS: Delphi-Strings besitzen eine abschließende implizite #0, aber nicht so schlimm ... doppelt hält besser. :stupid: |
AW: Externes Programm ausführen
Zitat:
Die obige Routine dürfte hierher stammen: ![]() |
AW: Externes Programm ausführen
Delphi.Narium, das hatte ich hier schon gefunden, es läuft nicht.
Auf -lang de verzichten ist auch keine Lösung, es gibt den Tag City er zeigt z.B. Düsseldorf falsch in Unicode an, doof. Ich habe es gerade ausprobiert, auf dem Rechner vor dem letzten Windows 10 Update werden Umlate z.B. Düsseldorf korrekt angezeigt. Die Windows Console ist wohl verändert worden. Was sagt ihr jetzt. Willie. |
AW: Externes Programm ausführen
Was wird denn von ExifTool auf der Kommandozeile für Düsseldorf ausgegeben? Sieht's dort richtig aus. Habe schon Kommandozeilenprogramme erlebt, die nicht den dort üblichen Zeichensatz nutzen, so dass dort Düsseldorf "falsch" ausgegeben wurde. Wenn dem so ist, scheitert auch eine Übersetzung nach Ansi, Unicode ...
Könntest Du bitte mal die Ausgabe von ExifTool auf der Kommandozeile für diesen Problemfall in eine Datei umleiten? Und dann (ohne eine von Dir vorgenommene Konvertierung) die Ausgabe, die Du in Deinem Programm erhältst? Und das dann beides hier mal anhängen, eventuell kommen wir damit ja irgendwie weiter. Wenn Du das entsprechende JPG mir dazulegen könntest, wäre nett, dann könnte man mal schauen, was da "wirklich" dinnesteht, um dem Zeichensatzwirrwarr, der momentan herrscht, mal auf die Sprünge zu kommen. |
AW: Externes Programm ausführen
Liste der Anhänge anzeigen (Anzahl: 2)
Also, wenn ich K-Dom.txt im Explorer öffne, wird Köln korrekt angezeigt. Ween ich erst Notepad öffne und dann K-Dom.txt öffne, wirden die Umlaute falsch angezeigt. Es geht um den Tag City.
Anbei Bild und Txt-Datei. P.S Stattdessen ein Bild von der schönen Nachbarstadt. |
AW: Externes Programm ausführen
Die Textdatei ist die unveränderte Ausgabe von ExifTool? Dann dürfte das nicht den "DOS-Zeichensatz" benutzen.
Hab' mir mal die aktuelle Fassung geholt. Bei mir sieht es so aus, als wären die Umlaute ... bei der Ausgabe auf der Kommandozeile UTF8. Wenn man die in eine Datei umgeleitet Ausgabe mit Totalcommander anschaut und dort als Zeichensatz UTF8 wählt, werden die Umlaute korrekt angezeigt. |
AW: Externes Programm ausführen
Zitat:
Alles weitere später ... Schönen Abend Willie. |
AW: Externes Programm ausführen
Dir ist im Öffnen-Dialog des Notpad etwas aufgefallen?
Wenn die Datei per Parameter geöffnet wird, dann läuft eine Automatik über die Datei und erkennt das UTF-8. Beim manuellen Öffnen mußt du die Standard-Codierung angeben und die steht nunmal auf ANSI, wenn du das nicht änderst. Problem: Die Datei ist zwar UTF-8, aber ohne explizite Angabe der Codierung -> ![]() Das Selbe gibt übrigens auch für LoadFromFile und den TFileStream -> Standard-Kodierung über den Encoding-Parameter. |
AW: Externes Programm ausführen
Hallo, ich habe mir Folgendes ausgedacht, es funktioniert zuerst mal. Nach den vielen Pleiten vielleicht ein Fortschritt. In meinem Archiv gefunden.
Delphi-Quellcode:
Willie.
function Ex195(const s: string): string;
var // Die deutschen Umlaute + ß werden falsch dargestellt (Unicode) po: Integer; ch: Char; // Durch Ausprobieren habe ich die Codes herausbekommen begin // erst #195 dann Zeichen ... - 16-10-2008 Result:=s; // Utf8ToAnsi() von Delphi macht genau das po:=Pos(#195,Result); while (Length(Result) > 0) and (po > 0) do begin ch:=Result[Po+1]; System.Delete(Result,po,2); case ch of #$84: ch:='Ä'; #$96: ch:='Ö'; #$9C: ch:='Ü'; #$A4: ch:='ä'; #$B6: ch:='ö'; #$BC: ch:='ü'; #$9F: ch:='ß'; else ch:='.' end; System.Insert(ch,Result,po); po:=Pos(#195,Result,Succ(po)) end end; |
AW: Externes Programm ausführen
In dem von dir angehängten Bild finde ich nicht die Informationen, die du ausgelesen hast. Kannst du mal das Original einstellen oder zumindest eins, in dem alle Informationen erhalten geblieben sind?
PS: Ich denke mal, ich habe die Lösung gefunden, und zwar ![]() Probiere mal folgende beiden Kommandos:
Delphi-Quellcode:
dann
exiftool.exe -charset IPTC=UTF8 -city=Köln -lang de C:\Temp\K-Dom.jpg
Delphi-Quellcode:
.
exiftool.exe C:\Temp\K-Dom.jpg -w! .txt
Wenn du meine Lösung mit Delphi verwendest, dann musst du
Delphi-Quellcode:
nochmal explizit angeben:
-charset IPTC=UTF8
Delphi-Quellcode:
exiftool.exe -k -a -u -g1 -lang de -charset IPTC=UTF8 C:\Temp\K-Dom.jpg
|
AW: Externes Programm ausführen
Hallo
-charset IPTC=UTF8 in den Parameter aufnehmen, hilft bei mir nicht!!!
Delphi-Quellcode:
Damit funktioniert es! Bei Delphi 2005 gab es diese Funktion noch nicht, deshalb mein Eigenkonstrukt, das ebenfalls funktioniert. Warum sollte ich das nicht nutzen. Ich habe die Exiftool-Textdatei vom JPG-Bild mit einem Hexeditor ausgewertet.
s:=UTF8ToAnsi(ETout.Text);
Wiellie. |
AW: Externes Programm ausführen
Delphi 7 hatte doch UTF8ToAnsi schon in der System.pas. Und bei Delphi 2005 soll das nicht mehr dabei sein?
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:09 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