Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Bedingt Prozedur aufrufen (https://www.delphipraxis.net/107213-bedingt-prozedur-aufrufen.html)

CRoSSi 24. Jan 2008 09:10


Bedingt Prozedur aufrufen
 
Hallo,
ich bin neu hier und habe mal ne frage..

weiß jemand wie man eine prozedur bedingt einbinden kann? Also wie man sie aufruft weiß ich, das ist nicht das Problem.
hatte mir das so ca vorgestellt: if var=1 then procedure usw.. hoffe mein Problem ist nachvollziehbar.

Danke schonmal für antworten
Christoph

DeddyH 24. Jan 2008 09:12

Re: Bedingt Prozedur aufrufen
 
Meinst Du so?
Delphi-Quellcode:
if var = 1 then
  Machwas
else
  MachwasAnderes;
P.S.: Willkommen in der DP :dp:

CRoSSi 24. Jan 2008 09:27

Re: Bedingt Prozedur aufrufen
 
ne das ist ja klar.. man muss die przedur doch definiern, sodass man die aufrufen kann.. und ich meien die definition dass man die irgendwie in ne if packt. Konkret würde ich des so meinen:

Delphi-Quellcode:
if var=1 then
   begin
   procedure PortOut(Port : Word; Data : Byte);stdcall; external 'io.dll';
   end;
Bekomme sonst ne Fehlermeldung wo der port Treiber nicht installiert ist.

Die Muhkuh 24. Jan 2008 09:30

Re: Bedingt Prozedur aufrufen
 
Dann musst Du die externen Funktionsaufrufe dynamisch laden und vorher prüfen, ob die Porttreiber installiert sind.

Das, was Du jetzt meinst, wird so nicht funktionieren.

Klaus01 24. Jan 2008 09:33

Re: Bedingt Prozedur aufrufen
 
Guten Morgen,

vielleicht kannst Du mit defines arbeiten:

Zitat:

Zitat von DelphiHilfe
Type Conditional compilation
Syntax {$IF expression}
Remarks

Compiles the source code that follows it if expression is True. expression must conform to Object Pascal syntax and return a Boolean value; it may contain declared constants, constant expressions, and the functions Defined and Declared.
For example,

{$DEFINE CLX}

const LibVersion = 2.1;

{$IF Defined(CLX) and (LibVersion > 2.0) }
... // this code executes
{$ELSE}
... // this code doesn't execute

{$IFEND}

{$IF Defined(CLX) }
... // this code executes
{$ELSEIF LibVersion > 2.0}
... // this code doesn't execute
{$ELSEIF LibVersion = 2.0}
... // this code doesn't execute
{$ELSE}
... // this code doesn't execute
{$IFEND}

The special functions Defined and Declared are available only within $IF and $ELSEIF blocks. Defined returns True if the argument passed to it is a defined conditional symbol. Declared returns True if the argument passed to it is a valid declared Pascal identifier visible within the current scope.

The $IF and $ELSEIF directives are terminated with $IFEND, unlike other conditional directives that use the $ENDIF terminator. This allows you to hide $IF blocks from earlier versions of the compiler (which do not support $IF or $ELSEIF) by nesting them within old-style $IFDEF blocks. For example, the following construction would not cause a compilation error:

{$UNDEF NewEdition}

{$IFDEF NewEdition}
{$IF LibVersion > 2.0}
...
{$IFEND}
{$ENDIF}

$IF supports evaluation of typed constants, but the compiler doesn't allow typed constants within constant expressions. As a result,

const Test: Integer = 5;

{$IF SizeOf(Test) > 2}

...

is valid, while

const Test: Integer = 5;

{$IF Test > 2 } // error

...

generates a compilation error.

If your code needs to be portable between various versions of Delphi (as well as Kylix), you will need to test whether or not this directive is supported by the compiler. You can surround your code with the following directives:

$IFDEF conditionalexpressions

. // code including IF directive
. // only executes if supported
$ENDIF


DeddyH 24. Jan 2008 09:33

Re: Bedingt Prozedur aufrufen
 
Schau Dir dazu mal z.B. diesen Thread an.

[edit] @Klaus: Ich denke, bedingte Kompilierung ist nicht das, was er sucht. [/edit]

Die Muhkuh 24. Jan 2008 09:35

Re: Bedingt Prozedur aufrufen
 
Klaus,

das geht leider nicht, da er mit den DEFINES nicht überprüfen kann, ob die Porttreiber installiert sind ;)

CRoSSi 24. Jan 2008 09:36

Re: Bedingt Prozedur aufrufen
 
:wiejetzt:
wie mache ich das?
mir reicht das schon wenn var=1 ist dass er dann die die funktion aufruft? weil var ist entweder 1 oder 0 bei 0 soll er einfach weiter machen und bei 1 soll die funktion geladen werden. Mehr brauche ich ja nicht. Das würde locker reichen.. Aber da ist das große fragezeichen wie macht man sowas am besten?

thx schonmal

oki 24. Jan 2008 09:41

Re: Bedingt Prozedur aufrufen
 
Zitat:

Zitat von CRoSSi
weil var ist entweder 1 oder 0 bei 0 soll er einfach weiter machen und bei 1 soll die funktion geladen werden. Mehr brauche ich ja nicht. Das würde locker reichen.. Aber da ist das große fragezeichen wie macht man sowas am besten?

thx schonmal

Was heißt bei dir geladen? Du meinst nicht zufällig ausführen?

Wenn Die Funktion geladen werden soll (aus DLL?), dann mußt du sie wie vorher schon gesagt dynamisch einbinden. Gib aber erst mal mehr Infos was du mit laden meinst.

Gruß oki

[edit] Sorry, hatte den zweiten Post übersehen. Also aus DLL! Dann mußt du dynamisch laden und vor der Procedurezuweisung prüfen. [/edit]

DeddyH 24. Jan 2008 09:43

Re: Bedingt Prozedur aufrufen
 
Schau Dir entweder meinen verlinkten Thread an oder arbeite dieses Tutorial von Olli mal durch.

CRoSSi 24. Jan 2008 09:45

Re: Bedingt Prozedur aufrufen
 
Meine mit geladen:
Delphi-Quellcode:
procedure PortOut(Port : Word; Data : Byte);stdcall; external 'io.dll';
Aber wie funktioniert das Dyamisch? Habe das noch nicht ganz so kappiert..wie es in dem einen thread (s.o.) beschrieben ist.
Evtl kann man mir jemand nen gutes beispiel machen?

Thx nochmal

DeddyH 24. Jan 2008 09:48

Re: Bedingt Prozedur aufrufen
 
Zitat aus Ollis Tut:
Zitat:

Beispiel: Dynamischer Import von DLL-Funktionen
Der dynamische Import funktioniert, wie schon gesagt, über das Holen der Adresse der zu
importierenden Funktion durch den Aufrufer.
Zuallererst muß der Aufrufer aber auch die Syntax der Funktion bekannt gemacht bekommen. Auch
wenn ein Funktionsaufruf „untendrunter“ quasi nur ein Sprung an eine bestimmte Adresse ist, kann
man ja in seinem Programm nicht wild an irgendeine Adresse springen lassen – wie sollen da die
Parameter übergeben werden? Es muß also ein sogenannter Funktionsprototyp her. In C(++) sind
die Funktionsprototypen meist in einer Header-Datei19 aufgeführt. Dies ist auch der Grund warum
diese vorher nach Delphi (ObjectPascal) übersetzt werden müssen (siehe Appendix A). Ähnlich wie
in C(++) ist die Funktionsprototypen-Deklaration in Delphi auch nur eine normale Typendeklaration:
Delphi-Quellcode:
type
TFNOneFunction = function(param1, param2, param3: Cardinal): integer;
TFNOneFunction_CDECL = function(param1, param2, param3: Cardinal): integer;
cdecl;
TFNOneFunction_STDCALL = function(param1, param2, param3: Cardinal): integer;
stdcall;
TFN ist übrigens in Delphi eine offiziell anerkannte Notation20 für Funktionstypen.
Da wir die Typen deklariert haben, brauchen wir nun noch die entsprechenden Variablen:
Delphi-Quellcode:
var
OneFunction: TFNOneFunction = nil;
OneFunction_CDECL: TFNOneFunction_CDECL = nil;
OneFunction_STDCALL_: TFNOneFunction_STDCALL = nil;
Die Variablen müssen global deklariert sein um sie mit nil initialisieren zu können, denn Delphi
erlaubt das Vorinitialisieren von Variablen nur im globalen Kontext. Nun müssen wir uns in einer, ich
schlage vor getrennten Funktion, die Adressen oder sogenannten Eintrittspunkte der Funktionen
holen:
Delphi-Quellcode:
Procedure GetEntryPoints;
var
lib:THandle;
begin
lib := LoadLibrary(@szNameDLL[1]);
case lib = 0 of
TRUE:
begin
@OneFunction_CDECL := @whatifnoentry;
@OneFunction := @whatifnoentry;
@OneFunction_STDCALL_ := @whatifnoentry;
messagebox(0, @dll_notloaded[1], nil, 0);
end;
else
begin
@OneFunction := GetProcAddress(lib, @szNameOneFunction[1]);
if not Assigned(OneFunction) then @OneFunction := @whatifnoentry;
@OneFunction_CDECL := GetProcAddress(lib, @szNameOneFunction_CDECL[1]);
if not Assigned(OneFunction_CDECL) then @OneFunction_CDECL :=
@whatifnoentry;
@OneFunction_STDCALL_ := GetProcAddress(lib, @szNameOneFunction_STDCALL[1]);
if not Assigned(OneFunction_STDCALL_) then @OneFunction_STDCALL_ :=
@whatifnoentry;
end;
end;
Man kann das Handle durch einen Aufruf von FreeLibrary() freigeben. Dies wird aber auch von
Windows erledigt, wenn der Prozeß beendet wird.

CRoSSi 24. Jan 2008 09:58

Re: Bedingt Prozedur aufrufen
 
Muss mich da wohl mal reinarbeiten.. Komme damit gerade nicht klar.. Mache das zum erstenmal mit dll's. evtl kann mir ja jemand nen Beispiel auf mich zugeschnitten machen dass ich das mal sehe. weil mit dem tutorial komme ich noch nicht so zurecht. evtl hilft mir dass Beispiel dann weiter.. und ich verstehe das tutorial richtig.

Thx nochmal für die ganzen antworten schon.

DeddyH 24. Jan 2008 09:59

Re: Bedingt Prozedur aufrufen
 
Du könntest das im Prinzip so machen:
Delphi-Quellcode:
type TPortOut = procedure(Port : Word; Data : Byte);stdcall;

...

var
  MyPortOut: TPortOut = nil;

...

var aHandle: THandle;
begin
  if var = 1 then
    begin
      aHandle := LoadLibrary('io.dll');
      if aHandle <> 0 then
      try
        @MyPortOut := GetProcAddress(aHandle,'PortOut');
        if Assigned(MyPortOut) then
          MyPortOut(aWord,aData);
      finally
        FreeLibrary(aHandle);
      end;
    end;
end;
Getippt und nicht getestet.

CRoSSi 24. Jan 2008 10:12

Re: Bedingt Prozedur aufrufen
 
So habe das mal probiert..geht leider nicht. Habe
Delphi-Quellcode:
TPortOut = procedure(Port : Word; Data : Byte);stdcall;
bei type angeben aber er sagt: BEZEICHNER ERWARTET ABER PROCEDURE GEFUNDEN

Wenn alles soweit läuft kann ich die Prozedur dann ganz normal aufrufen mit PORTOUT(..)?

DeddyH 24. Jan 2008 10:19

Re: Bedingt Prozedur aufrufen
 
Komisch, bei mir geht das. Und zum Ausführen schau Dir mein Beispiel noch einmal an. Ich versuche, die Adresse der Prozedur in der DLL zu finden und führe sie falls gefunden aus.
Delphi-Quellcode:
if Assigned(MyPortOut) then
  MyPortOut(aWord,aData);

RavenIV 24. Jan 2008 10:22

Re: Bedingt Prozedur aufrufen
 
Zitat:

Zitat von CRoSSi
:wiejetzt:
wie mache ich das?
mir reicht das schon wenn var=1 ist dass er dann die die funktion aufruft? weil var ist entweder 1 oder 0 bei 0 soll er einfach weiter machen und bei 1 soll die funktion geladen werden. Mehr brauche ich ja nicht. Das würde locker reichen.. Aber da ist das große fragezeichen wie macht man sowas am besten?

thx schonmal

Man hat Dir Links zu Tutorials gegeben.
Diese sind sehr gut und eigentlich auch verständlich geschrieben.

Setz Dich also hin und arbeite diese Tutorials Schritt für Schritt durch.
Eventuell solltest Du auch ein kleines Testprojekt der Tutorials durcharbeiten oder selber eines anlegen.

Es wird Dir hier niemand eine fertige Lösung zusammenschustern.
Eigeninitiative ist gefragt.

CRoSSi 24. Jan 2008 11:09

Re: Bedingt Prozedur aufrufen
 
Ja ich arbeite mich jetzt das tutorial mal durch muss da nur gucken wie ich das zeitlich halt schaffe..mache das ja nicht hauptberuflich.. :-D

aber danke an alle für die antworten

CRoSSi 30. Jan 2008 12:37

Re: Bedingt Prozedur aufrufen
 
So ich habe mir das Tut usw mal angeschaut und noch nen bisschen gegoogelt und habe mal einige versuche gestartet..aber leider erfolgslos. Poste hier mal den Quelltext einer kleinen Test Unit evtl habt ihr ein paar vorschläge warum das nicht geht. Bin ja nicht so der fiteste im Programmieren. Hoffe deshalb auf weitere gute Lösungsansätze.

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);

  private
    { Private-Deklarationen }

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;


implementation

{$R *.dfm}
type TPortOut = procedure(Port:Word;Data:Byte); stdcall;

var  PortOut: TPortOut;
      Handle: THandle;

procedure TForm1.Button1Click(Sender: TObject);
begin
Handle := LoadLibrary(PChar(ExtractFilePath(ParamStr(0))+'io.dll'));
if Handle <> 0 then begin
  @PortOut := GetProcAdress(Handle, 'PortOut');
  if @PortOut <> nil then begin
  PortOut($378,255);
  end;
FreeLibrary(Handle);
end;

end.
Hoffe habe das jetzt so halbwegs verstanden
Danke für antworten

oki 30. Jan 2008 14:22

Re: Bedingt Prozedur aufrufen
 
So wird ein Schuh draus:
Delphi-Quellcode:

{$R *.dfm}
type TPortOut = procedure(Port:Word;Data:Byte); stdcall;

var  PortOut: TPortOut = nil;
      AHandle: THandle = 0;

implementation

procedure TForm1.Button1Click(Sender: TObject);
begin
  AHandle := LoadLibrary('io.dll');
  if AHandle <> 0 then begin
    PortOut := GetProcAdress(AHandle, 'PortOut');
    if PortOut <> nil then begin
    PortOut($378,255);
  end;
  FreeLibrary(AHandle);
end;
Gruß oki

[edit] Handle auf AHandle [/edit oki]

DeddyH 30. Jan 2008 14:43

Re: Bedingt Prozedur aufrufen
 
Und das FreeLibrary noch eine Zeile höher vor das end ;)

oki 30. Jan 2008 14:46

Re: Bedingt Prozedur aufrufen
 
Upps,

klar, sorry!

Gruß oki

Muetze1 30. Jan 2008 17:05

Re: Bedingt Prozedur aufrufen
 
Zitat:

Zitat von oki
So wird ein Schuh draus:

Bezweifle ich. Du machst einen Aufruf der Procedure beim Zuweisen mit GetProcAddress und du rufst die Funktion innerhalb der If Anweisung auf. Da meckert beide male der Compiler. Er hatte es schon richtig.

Die Frage ist eher: Was klappt nicht? Passiert einfach nichts? Da ist dann die Frage: kann er die DLL nicht laden oder den Export in der DLL nicht finden?

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  AHandle := LoadLibrary('io.dll');
  if AHandle <> 0 then
  begin
    @PortOut := GetProcAdress(AHandle, 'PortOut');
    if assigned(PortOut) then
    begin
      PortOut($378,255);
    end
    else
      ShowMessage('Funktion in der DLL nicht gefunden!');

    FreeLibrary(AHandle);
  end
  else
    ShowMessage('DLL nicht gefunden!');
end;

oki 30. Jan 2008 17:14

Re: Bedingt Prozedur aufrufen
 
Hi Muetze1,

ich hab mich durch die miese Formatierung etwas durcheinander bringen lassen. Der Compiler sollte aber eher wegen der fehlenden End's meckern.

so sollte es aber doch richtig sein ... oder bin ich jetzt blind :gruebel:
Delphi-Quellcode:
type TPortOut = procedure(Port:Word;Data:Byte); stdcall;

var  PortOut: TPortOut = nil;
      AHandle: THandle = 0;

implementation

procedure TForm1.Button1Click(Sender: TObject);
begin
  AHandle := LoadLibrary('io.dll');
  if AHandle <> 0 then begin
    PortOut := GetProcAdress(AHandle, 'PortOut');
    if PortOut <> nil then
      PortOut($378,255);
    FreeLibrary(AHandle);
  end;
end;
Gruß oki

[edit] ich formatiere mich hier noch um Kopf und Kragen [/edit]

Muetze1 30. Jan 2008 17:18

Re: Bedingt Prozedur aufrufen
 
Zitat:

Zitat von oki
so sollte es aber doch richtig sein ... oder bin ich jetzt blind :gruebel:

Entweder bin ich auf dem Holzweg, aber PortOut ist vom Typ TPortOut und das ist ein definierter Typ einer procedure. Wenn du also nun irgendwo einfach nur PortOut schreibst (wie du es ja beim endgültigen Aufruf tust), dann ruft er die Procedure auf. Dies schreibst du nun aber auch bei der Zuweisung mit GetProcAdress() und bei der If Abfrage. Somit will der Compiler dort einen Aufruf machen, da du ja eindeutig die Procedure aufrufst. Von daher meckert er die fehlenden Parameter an.

Deshalb muss man die Adresse zuweisen beim GetProcAdress(), also mit dem @ davor. Bei der If Abfrage will man schliesslich auch nicht den Rückgabewert der Procedure mit Nil vergleichen sondern die abgelegte Adresse der Funktion. Von daher auch dort ein @ davor - oder - mit Assigned() prüfen.

oki 30. Jan 2008 17:27

Re: Bedingt Prozedur aufrufen
 
Hi,

Das mit dem assigned verwende ich bei mir eigentlich auch immer. Hab an dieser Stelle aus dem Thread kopiert und mir nichts dabei gedacht, da das nil in der globalen Variablenzuweisung auch nicht angemeckert wird. Somit geb ich dir ungeprüft recht. Bei der Zuweisung der Proceduradresse klappt das aber definitiv ohne @ !!! Hab ich vorherige Woche grad mit einer dynamischen DLL-Einbindung gemacht. Ist getestet. Entweder es geht wirklich auch grundsätzlich so, oder mein D2007 hilft im Hintergrund nach.

Gruß oki

Muetze1 30. Jan 2008 17:42

Re: Bedingt Prozedur aufrufen
 
Ok, das mit dem GetProcAddress() kann ich nachvollziehen, das meckert er mir beim BDS2006 auch nicht mehr an. Die If Anweisung jedoch wird als Aufruf betrachtet. Das ist mir neu, ich teste gleich nochmal die älteren Versionen.

Ok, bis runter zu D5 klappt die GetProcAddress() Zuweisung ohne das @. Somit stimmt meine Aussage mit dem @ bei dem Teil nicht, es ist optional. Wieder was gelernt - aber was soll's, ich hab' ja keine Ahnung...

oki 30. Jan 2008 17:49

Re: Bedingt Prozedur aufrufen
 
Zitat:

Zitat von Muetze1
Die If Anweisung jedoch wird als Aufruf betrachtet.

Dazu ziehe ich meine Meinung zurück und behaupte das Gegenteil :mrgreen:

- aber was soll's, ich hab' ja keine Ahnung... :mrgreen: [heimliches Zitat]

gruß oki

CRoSSi 31. Jan 2008 21:00

Re: Bedingt Prozedur aufrufen
 
So irgendwie ghets immer noch nicht... irgendwie bin ich zu doof für die gnaze aktion oder es ist wirlioch noch irgendwo nen fehler drin. So muss es doch gehen aber warum sagt er mir bei GetProcAdress das es ein undefinierter Bezeichner ist? also mir fällt da jetzt garnichts mehr ein..habe davon die anse bald voll :twisted: das muss doch irgendwie gehen.

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
type TPortOut = procedure(Port:Word;Data:Byte); stdcall;

var  PortOut: TPortOut = nil;
      AHandle: THandle = 0;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  begin
  AHandle := LoadLibrary('io.dll');
  if AHandle <> 0 then begin
    PortOut := GetProcAdress(AHandle, 'PortOut');
    if PortOut <> nil then
      PortOut($378,255);
    end;
    FreeLibrary(AHandle);
  end;
end;

end.

Muetze1 31. Jan 2008 21:41

Re: Bedingt Prozedur aufrufen
 
MSDN-Library durchsuchenGetProcAddress()

oki 1. Feb 2008 06:07

Re: Bedingt Prozedur aufrufen
 
Schreibfehler,

Address mit doppeltem d

dann klappts auch mit dem Nachbarn!

Moin und Gruß oki

CRoSSi 1. Feb 2008 06:44

Re: Bedingt Prozedur aufrufen
 
Moin thx erstemal für euere antworten ich glaube man kommt der Lösung immer näher es gibt nur noch eine stelle wo er rummeckert.. :gruebel:. Und zwar bei
Delphi-Quellcode:
if PortOut <> nil then begin
da sagt er "nicht genügend wirkliche parameter". Was kann das sein? Habe die Unit von meinem test Prog auch nochmal kopiert:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
type TPortOut = procedure(Port:Word;Data:Byte); stdcall;

var  PortOut: TPortOut = nil;
      AHandle: THandle = 0;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  AHandle := LoadLibrary('io.dll');
  if AHandle <> 0 then begin
    PortOut:= GetProcAddress(AHandle, 'PortOut');
    if PortOut <> nil then begin
      PortOut($378,00);
    end;
    FreeLibrary(AHandle);
  end;
end;

end.
THX schonmal

oki 1. Feb 2008 06:49

Re: Bedingt Prozedur aufrufen
 
Moin Crossi,

du mußt auch die Beiträge lesen. Muetze1 und ich hatten das drei Beiträge vorher diskutiert. Bei der Abfrage auf nil muß das @ davor.
Schreib es so wie Muetze1 es gesagt hat:
Delphi-Quellcode:
if assigned(PortOut) then
oder so:
Delphi-Quellcode:
if @PortOut <> nil then
Gruß oki

CRoSSi 1. Feb 2008 06:53

Re: Bedingt Prozedur aufrufen
 
Jor hatte das @ nach meinem post nochmal probiert :oops: und es gehts endlich.. :bounce1: ein dickes Dankeschön an alle die bei diesem Thread mitgeholfen haben


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:27 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