AGB  ·  Datenschutz  ·  Impressum  







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

Wann wird fremde TForm ausgeblendet

Ein Thema von himitsu · begonnen am 13. Jun 2024 · letzter Beitrag vom 16. Jun 2024
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von himitsu
himitsu

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

Wann wird fremde TForm ausgeblendet

  Alt 13. Jun 2024, 22:05
Moin Moin,

wie "elegant" mitbekommen, wann eine fremde TForm freigegeben ausgeblendet wird?
egal wie (VCL oder NonVCL)

Freigeben ist einfach.
* einfach ein WinWintrol dranhängen ... mein HWND verschwindet, wenn der Parent verschwindet
* oder ein TComponent mit Owner dranhängen ... wird Parent freigegeben, dann ich auch

Aber leider dauert es "ewig", vom Ausblenden, bis zur Freigabe, drum wollte ich nun versuchen, mich ans "Hide" zu hängen.

* TApplicationEvents.OnMessage auf WM_DESTROY bzw. WM_QUIT ... unschön, weil dann ja bei ALLEM mein "Hook" drin
* Form.OnHide oder OnClose überschreiben
* WndProc der Form hooken (SetWindowLong+GWL_WNDPROC -> CM_VISIBLECHANGED)
* VMT des DoHide überschreiben
* * gefallem mit diese Hooks eigentlich nicht wirklich, da ich dort ja prinzipiell ja die Komponente selbst "verändern" würde (ungünstig, wenn ich einen Fehler machen würde)


WM_SHOWWINDOW bei meinen WinControl ausprobiert, aber es wird nie aufgerufen ... somit leider nicht möglich dort das SW_PARENTCLOSING prüfen zu wollen.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (13. Jun 2024 um 22:09 Uhr)
  Mit Zitat antworten Zitat
TomyN

Registriert seit: 8. Nov 2006
Ort: Bayreuth
244 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 08:28
Ich bin mir nicht sicher, ob ich die Frage richtig verstehe. Aktuell wäre mein Vorschlag https://learn.microsoft.com/en-us/wi...swindowvisible
Thomas Neumann
Meine Projekte
www.satlive.audio
www.levelcheck.de
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.604 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 09:05
Es geht also um eine "fremde" TForm im gleichen Delphi-Programm?

Willst Du etwas, das immer funktioniert, also für beliebige TForms? Oder reicht etwas, das für eine bestimmte TForm funktioniert?

TForm.OnHide wäre da das einfachste, sofern dieses Event nicht belegt ist. Wenn doch, aber der Wert sich nicht ändert, kann man den originalen Event speichern und ihn aus dem eigenen aufrufen, vor, oder nach dem eigenen Code.

Edit: "VCL oder non-VCL" bedeutet VCL oder FMX ? Oder sprechen wir hier doch nicht von einem Delphi-Programm?
Thomas Mueller

Geändert von dummzeuch (14. Jun 2024 um 09:17 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 12:17
Jupp, eine fremde Form im Programm.

Es ist ja nicht "meine" Form, und somit weiß ich nicht, ob nicht jetzt/irgendwann schon was am OnHide hängt. (Ja, eine Kopie des Wertes und dann das Aufrufen ... Problem ist dann, wenn irgendwann noch wer Anderes auch sowas macht)

Ich will einfach nur mitbekommen, wann sie ausgelendet wird, also eigentlich das Programm "anfängt" sich zu beenden.
Aber das so früh wie möglich. (über die "normalen" Wege der OTA, sind zwischen dem Verschwinden der MainForm aus der Taskleiste und meinem Taskbareintrag 30-60 Sekunden, wo man nix sieht, bis es wirklich weg ist)

z.B. die Hauptform vom Delphi, in einem Designtimepackage.

Edit: "VCL oder non-VCL" bedeutet VCL oder FMX ? Oder sprechen wir hier doch nicht von einem Delphi-Programm?
VCL oder direkt per WinAPI
z.B. das WM_SHOWWINDOW+SW_PARENTCLOSING hatte ich mit einem TPanel probiert (hätte aber auch eine TForm sein können) oder eben per CreateWindowEx.





Das Projekt macht jetzt nicht viel,
  • also zu Beginn den SplashScreen in der Taskleiste
    (wenn Delphi im Hintergrund aufgeht und man noch was Anderes macht ... und wo Delphi vielleicht hängenbleibt, weil z.B. Probleme beim Laden des letzten Projektes, mit Warten in einem Dialog ... unbemerkt im Hintergrund versteckt)
  • sowie beim Beenden ebenfalls in der Taskleiste (hier ist allerdings aktuell öfters noch eine längere Lücke ... DevExpress und Anderes wird zwischenzeitlich entladen)
    bis die BDS.exe wirklich komplett weg ist

    Delphi bleibt manchmal leise hängen, oder eventuell auch nur mit 100% CPU minutenlang irgendwas machend,
    und dann knallt es im FinalBuilder, weil Designtimepackages sich nicht neu erstellen lassen, da Datei gesperrt.
Delphi-Quellcode:
unit Package1Unit;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Classes,
  System.Win.ComObj, Winapi.ShlObj, Winapi.Dwmapi,
  Vcl.ExtCtrls, Vcl.Forms;

//procedure Register;

implementation

type
  TStartDummy = class
  private
    class procedure AssignToStart;
    class procedure WaitTimer(Sender: TObject);
  end;

  TDestroyDummy = class(TPanel) // TPanel wegen WMShowWindow (eigentlich TComponent)
  public
    procedure BeforeDestruction; override;
  private
    procedure WMShowWindow(var Msg: TWMShowWindow); message WM_SHOWWINDOW;
  end;

class procedure TStartDummy.AssignToStart;
var
  Taskbar: ITaskbarList3;
begin
  for var i := Screen.CustomFormCount - 1 downto 0 do
    if (Screen.CustomForms[i].ClassType = TForm) and (Screen.CustomForms[i].Caption = 'SplashScreen') then
      begin
        // in Taskleiste anteigen
        ShowWindow(Screen.CustomForms[i].Handle, SW_HIDE);
        SetWindowLong(Screen.CustomForms[i].Handle, GWL_EXSTYLE, GetWindowLong(Screen.CustomForms[i].Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW or WS_EX_APPWINDOW);
        ShowWindow(Screen.CustomForms[i].Handle, SW_SHOW);

        // Texte und Arbeitsanzeige
        Screen.CustomForms[i].Caption := 'Delphi wird gestartet';
        Taskbar := CreateComObject(CLSID_TaskbarList) as ITaskbarList3;
        {CheckOSError}(Taskbar.SetProgressState(Screen.CustomForms[i].Handle, TBPF_INDETERMINATE));
        //{CheckOSError}(Taskbar.SetThumbnailTooltip(Screen.CustomForms[i].Handle, 'Delphi wird gestartet'));
      end;

  //TDestroyDummy.Create(Application.MainForm); // an Hauptfenster hängen
  with TDestroyDummy.Create(Application.MainForm) do begin // an Hauptfenster hängen
    Parent := Application.MainForm;
    BevelOuter := TPanelBevel.bvNone;
    Width := 1;
    Height := 1;
    TabStop := False;
    Visible := True;
  end;
end;

class procedure TStartDummy.WaitTimer(Sender: TObject);
var
  B: Boolean;
begin
  try
    B := Assigned(Application) and Assigned(Application.MainForm);
    for var i := Screen.CustomFormCount - 1 downto 0 do
      if (Screen.CustomForms[i].ClassType = TForm) and (Screen.CustomForms[i].Caption = 'SplashScreen') then
        B := True;

    if B then begin
      TStartDummy.AssignToStart;
      Sender.Free;
    end;
  except
  end;
end;

procedure TDestroyDummy.BeforeDestruction;
var
  WndClass: TWndClass;
  TaskWnd: HWND;
  Taskbar: ITaskbarList3;
  Param: BOOL;
begin
  try
    FillChar(WndClass, SizeOf(WndClass), 0);
    WndClass.lpfnWndProc := @DefWindowProc;
    WndClass.hInstance := HInstance;
    WndClass.hIcon := 0;
    WndClass.lpszClassName := 'TaskbarDestroyDummy';
    {Win32Check}(RegisterClassW(WndClass) {<> 0});

    TaskWnd := CreateWindowEx(WS_EX_TOOLWINDOW or WS_EX_APPWINDOW, WndClass.lpszClassName, PChar('Delphi wird beended'),
      WS_VISIBLE {or WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS}, 100, 100, 0, 0, 0, 0, HInstance, nil);
    {Win32Check(TaskWnd <> 0);}

    Taskbar := CreateComObject(CLSID_TaskbarList) as ITaskbarList3;
    {CheckOSError}(Taskbar.SetProgressState(TaskWnd, TBPF_INDETERMINATE));
    {CheckOSError}(Taskbar.SetThumbnailTooltip(TaskWnd, 'Delphi wird beendet'));

    Param := True;
    {CheckOSError}(DwmSetWindowAttribute(TaskWnd, DWMWA_FORCE_ICONIC_REPRESENTATION, @Param, SizeOf(BOOL)));
    {CheckOSError}(DwmSetWindowAttribute(TaskWnd, DWMWA_HAS_ICONIC_BITMAP, @Param, SizeOf(BOOL)));

    inherited;
  except
  end;
end;

procedure TDestroyDummy.WMShowWindow(var Msg: TWMShowWindow);
begin
  MessageBox(0, PChar(IntToStr(Msg.Status)), nil, 0);
end;

//procedure Register; // wenn in HKEY_CURRENT_USER\Software\Embarcadero\BDS\22.0\Known IDE Packages
//begin
// TStartDummy.AssignToStart;
//end;

initialization
  with TTimer.Create(nil) do begin // wenn in HKEY_CURRENT_USER\Software\Embarcadero\BDS\22.0\Known Packages
    OnTimer := TStartDummy.WaitTimer;
    Interval := 1;
    Enabled := True;
  end;

finalization
  try
    if Assigned(Application) and Assigned(Application.MainForm) then
      for var C in Application.MainForm do
        if C is TDestroyDummy then begin
          C.Free;
          Break;
        end;
  except
  end;

end.
37 KB als Release (2-3 MB als Debug)

"register" kommt erst eine Weile nach dem erscheinen des SplashScreen (Known IDE Packages früher oder Known Packages bissl bis viel später)
"initialization" im Known IDE Packages leider schon vor dem SplashScreen (drum der böse Timer)



Und dann das die Registrierung von "Known Packages" ins "Known IDE Packages" verschieben,
bzw. garnicht das Package "installieren" und direkt den Eintrag dort rein.
C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\Package1.bpl

Achtung, ist es im "Known IDE Packages" registriert, dann lässt sich das Projekt im Delphi nicht mehr kompilieren. (vorher also entfernen oder umbennen ... _ anhängen)

Der Code ist für Delphi 11.
Ab Delphi 12 ist es nochmal extrem einfacher, da dort die VCL alles bietet,
von Form.ShowInTaskBar über TTaskbar (Form.TaskbarHandler).

Delphi-Quellcode:
// Der SplashScreen ist eine manuell zusammengebaute TForm.
SplashScreen.Caption := 'Delphi startet';
SplashScreen.ShowInTaskBar := True;
TaskBar := TTaskBar.Create(SplashScreen); // SplashScreen.TaskbarHandler
TaskBar.ProgressState := TTaskBarProgressState.Indeterminate;
TaskBar.ToolTip := 'Delphi startet';

Echt mal, ich verstehe einfach nicht, warum sich Emba seit Jahrzehnten dagegen wehrt, beim Starten das Delphi in der Taskleiste anzuzeigen,
also SetWindowLong+WS_EX_APPWINDOW, bzw. aktuell TForm.ShowInTaskBar.
(wenigsten ist der nicht StayOnTop)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (14. Jun 2024 um 17:01 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.604 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 13:48
Ach, es geht um die Delphi-IDE. Warum hast Du das nicht gleich geschrieben?

Zum Hooken von Events in der IDE hätte ich noch folgendes beizutragen:

https://blog.dummzeuch.de/2016/03/28...ins-revisited/

Allerdings bin ich wohl der einzige, der sich an diesen "Standard" hält (immerhin 2 Plugins), aber es kann nicht schaden, das zu tun.
Thomas Mueller
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 14:21
Hey, an einen Hook im Screen hatte ich auch schon gedacht. (change des ActiveControl/ActiveForm)

Leider hat TList kein OnChange, sondern nur ein virtuellen Notify.
Ein einfaches überschreiben der VMT würde alle TList hooken, aber immernoch enorm weniger, als ein ApplicationEvents.OnMessage.
Aber wenn, dann hätte ich wohl den TVirtualMethodInterceptor bemüht. (der kopiert ja die ClassInfo und hookt dort dann nur für diese Instanz)

An TScreen.FForms bzw. FCustomForms wäre ich über einen bösen Cast mit kopierter Klasse bin ich über die RTTI rangekommen.
Beim Hook des Notify war ich mir noch unsicher.
Delphi-Quellcode:
  var R := TRttiContext.Create.GetType(Vcl.Forms.TScreen);
  var L := R.GetField('FForms').GetValue(Screen).AsObject as TList;

  R := TRttiContext.Create.GetType(TList);
  R.GetMethod('Notify').VirtualIndex
Da hier in der OTA/NTA nichts möglich ist
und auch die VCL direkt nichts bietet,
suche ich halt einfach nur einen "schönen" Weg, möglichst mit nativen Mitteln des Delphi (VCL/GDI),
um rauszubekommen, wann diese TForm hidden wird.

Mir fällt grad ein, anstatt an die Screen->TList könnte ich auch direkt die VMT der TAppBuilder (DoHide)
(auch wenn Delphi bei vielen eigenen Klassen die erweiterte RTTI deaktiviert hat ... die VMT der ClassInfo bleibt)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (14. Jun 2024 um 14:25 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 16:42
Wow, die haben in D12 ja echt mal was verändert.
Der SplashScreen ist jetzt eine eigene Form-Klasse.

http://fnse.de/Delphi-in-Taskleiste.mp4 (oder siehe Anhang)
http://fnse.de/Delphi-in-Taskleiste2.mp4
Wollte erst die 12, aber dann fiel mir ein, dass man bei der 11 länger etwas von sieht.

Jetzt nur noch das ShowInTaskBar auf True und vielleicht noch ein TTaskbar drauf.
Muß ich wohl mal einen neuen FeatureRequest erstellen.


Selbst ein halbwegs frisches D12, noch ohne Unmassen an Erweiteurngen und Fremdkomponenten, braucht hier beim Beenden schon 10-15 Sekunden, bis es wirklich weg ist, nachdem IDE-Fenster und Taskbar-Button verschwunden sind.


OK, es war "erstmal" einfacher, als gedacht.
OnShow wird "aktuell" von Emba nicht verwendet, also hab ich mich dort angehängt.
(hab da eine billige Assigned-Prüfung mit Warnmeldung, falls die das ändern)

Also, für D11.3 und D12.1 hab ich's nun erstmal am Laufen.
  • Kompilieren (oder BPL aus ZIP)
  • das Package nicht installieren
    • für's Beenden ist es egal
    • aber beim Start reagiert es als IDE-Package besser (Known IDE Packages)
    • falls als normales Package, mit installieren, vorher das DEFINE in der PAS umstellen (Known Packages)
  • dann in der Registry das Package eintragen (nur wenn nicht "installiert")
    • Delphi 12
      HKEY_CURRENT_USER\Software\Embarcadero\BDS\23.0\Known IDE Packages
      C:\Users\Public\Documents\Embarcadero\Studio\23.0\Bpl\IsDelphiRunning.bpl
    • Delphi 11
      HKEY_CURRENT_USER\Software\Embarcadero\BDS\22.0\Known IDE Packages
      C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\IsDelphiRunning.bpl
    • Delphi 10 wird eventuell auch funktionieren
      davor muß aber garantiert noch bissl was angepasst werden
  • und sich freuen, dass Delphi in der Taskleiste nun endlich sagt ob und was es macht
  • .
  • Hab aber keine Ahnung, warum beim Beenden das Icon so lange braucht (hab es ja direkt beim RegisterClass via LoadIcon zugewiesen),
    aber OK, es kommt und zu sehn ist ja dennoch was ... und das war die Hauptsache.
  • Beim Start ist es auch fast sofort da (der Timer braucht halt bissl was ... muß ja auf's Application.ProcessMessages warten ),
    aber da es nun eine eigene Form ist, könnte ich mich in die Klasse Hooken (Create CreateWnd oder DoShow)

    Da ich beim Starten den SplashScreen dazu bringe sich in der Taskleiste zu zeigen, muß ich halt warten, bis jener da ist.
    Ich könnte, wie beim Beenden, einen eigenen Eintrag erstellen, aber so verschwindet er automatisch, sobald der SplashScreen durch die Hauptform ersetzt wird.
    Außerdem ist damit in der AeroPreview auch das Bild des SplashScreen drin.
Angehängte Dateien
Dateityp: zip Delphi-in-Taskleiste.mp4.zip (1,14 MB, 2x aufgerufen)
Dateityp: zip IsDelphiRunning.zip (27,0 KB, 2x aufgerufen)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (14. Jun 2024 um 17:24 Uhr)
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
346 Beiträge
 
#8

AW: Wann wird fremde TForm ausgeblendet

  Alt 14. Jun 2024, 17:15
From the video, i think i do understand the question, so here a suggest with different approach :
Replace BorlndMM.dll with one that load (just an import of one function might be enough) another DLL (yours) in this case BorlndMM.dll still serve as memory manager, but will invoke your dll before even the IDE start, don't forget to make your injected dll is not using share memory.
Kas
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Wann wird fremde TForm ausgeblendet

  Alt 15. Jun 2024, 02:04
Normal fällt einfach nicht auf, wenn Delphi startet und noch schlimmer, wenn es beim Starten im Hintergrund hängen bleibt.
Sowie, dass Delphi eigentlich noch offen ist, wenn es zu lange zum Beenden braucht. Hier ebenfalls nett, wenn es durch einen Fehler ewig unbemerkt hängen bleibt.
http://fnse.de/Delphi-in-Taskleiste-Normal.mp4
http://fnse.de/Delphi-in-Taskleiste-Extension.mp4

Was auch nicht gleich auffällt, wenn man Delphi ausversehn mehrfach startet.
Oder wenn es hängt, man denkt man hatte vielleicht vergessen zu klicken, bzw. nicht richtig geklickt, und startet es dann nochmals. (wenn man den Splashscreen nicht sieht, weil ein anderes Programm vorne liegt)
Die Splashscreens überdecken sich und in der Taskleiste taucht normal ja erst das Hauptfenster auf.
http://fnse.de/Delphi-in-Taskleiste-Doublestart.mp4

Komisch sieht es aus, wenn das Delphi im Hintergrund weiter/schneller ist und dann hinter/unter dem sichtbaren Splashscreen noch ein anderer Teil hervorragt. (bei genügend Erweiterungen, wenn sich das Fenster vergrößert)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (15. Jun 2024 um 02:22 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Wann wird fremde TForm ausgeblendet

  Alt 15. Jun 2024, 02:52
Zitat von dummzeuch:
even though they both hook Screen.OnFormChange
Ja, bei Verwendung dieser/solcher Events fragt ich mich das auch immer mal wieder.

Wenn man TApplicationEvents kennt, dann fragt man sich, warum es sowas nicht auch für Screen gibt, bzw. warum die TScreen-Events nicht auch im TApplicationEvents mit enthalten sind.

Zitat von dummzeuch:
First, there must be a Hook-class for each event type. There isn’t much that can be done about this since the method signature of each event is different and we don’t want to resort to assembly language
Wäre es nicht zu praktisch, wenn man hierfür die Technicken wie bei den "references of procedure" nutzen könnte?

OK, via RTTI-Invoke könnte man da bestimmt so einiges machen, aber "schön" ist das auch nicht.

Zitat von dummzeuch:
want the code to work with ancient Delphi versions back to Delphi 6
OK, diesbezüglich mach ich es mir einfach und mach es lieber "einfach", auch wenn dann alte Delphis rausfallen.
Auch bei WinAPI hab ich aufgegeben auf biegen und brechen Altes unterstüzen zu wollen (9x ist tot , XP ist tot ähhh 7 ist tot die ersten 10 sind tot)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (15. Jun 2024 um 03:01 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 12:41 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