Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Wake on LAN Problem :-( (https://www.delphipraxis.net/116214-wake-lan-problem.html)

TimmA 25. Jun 2008 07:55


Wake on LAN Problem :-(
 
Hallo!

ich habe vor ein kleines Programm zu schreiben das zum einen über einen Button einen Rechner im Netzwerk starten soll und zum anderen über einen anderen Button eine EXE des Fernwartngsprogramm starten soll. Also nichts wildes, mehr bekomme ich auch nicht mehr hin nach Jahren von Programmierpause :-).

Der Button zum starten der EXE war ja nicht das Problem, zum Thema WOL fand ich hier auch einige Threads, allerdings hat bei mir garnichts davon funktioniert.
Hat jemand eine Idee wie ich diese Funktion so simple wie möglich in mein kleines Programm einfügen kann?
Habe Delphi7 Prof.

Gruß TA

DGL-luke 25. Jun 2008 08:30

Re: Wake on LAN Problem :-(
 
afaik musst du dazu ein "magic package" schicken. Wenn die Netzwerkkarte des angesprochenen PCs das empfängt, leitet es das ans BIOS weiter, was dann bei entsprechender Einstellung den PC startet.

Das ist so die Strecke, auf der was schieflaufen kann...

TimmA 25. Jun 2008 08:39

Re: Wake on LAN Problem :-(
 
Habe das ganze schon mit einem fertigen Tool getestet ob es überhaupt funktioniert, das geht.

Hat jemand evtl. ein Beispiel für mich was funktioniert?
habe davon nämlich nicht wirklich viel Ahnung, und wenn ich als Grundlage eines der Beispiele aus der Suche hier nehme funktioniert es auch nicht.

divBy0 25. Jun 2008 08:43

Re: Wake on LAN Problem :-(
 
Ich hab das bei mir schon mal mit diesem Code gemacht.

Ansonsten steht hier noch einiges interessantes dazu.

TimmA 25. Jun 2008 09:21

Re: Wake on LAN Problem :-(
 
danke dir, mit diesem Code z.B. habe ich es auch schon getestet, beim Anklicken bekomme ich nur eine Exeption.

was müsste ich denn noch alles an diesem Code anpassen?

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Data, temp: string;
  k, n: integer;
begin
  Data := '';
  for k := 0 to 5 do
  begin
    Data := Data + Chr(StrToInt('$FF')); // 6x add a FF / 6x ein FF hinzufügen
  end;
  temp := StringReplace(Edit1.Text, '-', '', [rfReplaceAll]);
  for k := 0 to 15 do
  begin
    temp := StringReplace(Edit1.Text, '-', '', [rfReplaceAll]);
    for n := 0 to 5 do
    begin
      // 16x add Target-Mac-Adress / 16x die Ziel-Macadresse hinzufügen
      Data := Data + Chr(StrToInt('$' + temp[1] + temp[2]));
      Delete(temp, 1, 2);
    end;
  end;
 
  //Example with TIdUDPClient of Indy
  //IdUDPClient1.Send('255.255.255.255', '80', Data); // Send it / Verschick es
end;

Wenn ich das so übernehme und in Edit1 meine Mac-Adresse mit- Trennzeichen schreibe passiert nichts, ich muss also noch die // vor
IdUDPClient1.Send('255.255.255.255', '80', Data); wegmachen, oder nicht? warum ist das eigentlich kommentiert?

Wenn ich also die // rausnehme kann ich nicht compilieren, er meckert die '' bei '80' an!

Wenn ich die wegmache mache passiert auch nichts wenn ich den Button drücke:-(

Deinen 2. Link habe ich auch schon gefunden, allerdings ist der von 2003 und wollte den nicht noch mal aufwühlen. Die Demos zum download in diesem Thread sind leider nicht mehr verfügbar.

divBy0 25. Jun 2008 09:30

Re: Wake on LAN Problem :-(
 
Zitat:

Zitat von TimmA
Wenn ich das so übernehme und in Edit1 meine Mac-Adresse mit- Trennzeichen schreibe passiert nichts, ich muss also noch die // vor
IdUDPClient1.Send('255.255.255.255', '80', Data); wegmachen, oder nicht? warum ist das eigentlich kommentiert?

Wenn ich also die // rausnehme kann ich nicht compilieren, er meckert die '' bei '80' an!

Wenn ich die wegmache mache passiert auch nichts wenn ich den Button drücke:-(

Deinen 2. Link habe ich auch schon gefunden, allerdings ist der von 2003 und wollte den nicht noch mal aufwühlen. Die Demos zum download in diesem Thread sind leider nicht mehr verfügbar.

IdUDPClient1 darf natürlich nicht auskommentiert sein. Die neueren Indys wollen den Port als Integer, die alte Version wollte ihn anscheinend als String.

Das müsste eigentlich funktionieren. Schau dir doch mal den Netzwerkverkehr mit Wireshark an, da solltest du das MagicPacket finden.

TimmA 25. Jun 2008 09:33

Re: Wake on LAN Problem :-(
 
werde ich machen, die 255.255.255.255 ist korrekt? oder muss ich das auf 192.168.146.255 anpassen?

divBy0 25. Jun 2008 09:35

Re: Wake on LAN Problem :-(
 
Liste der Anhänge anzeigen (Anzahl: 1)
255.255.255.255 ist korrekt, da das ganze als UDP-Broadcast läuft, damit wird das Paket einfach an alle gesendet. Die Netzwerkkarte mit der entsprechen MAC-Adresse erkennt es und leitet es dann weiter.

[EDIT] Screenshot angehängt [/EDIT]

TimmA 25. Jun 2008 09:52

Re: Wake on LAN Problem :-(
 
Liste der Anhänge anzeigen (Anzahl: 1)
Habe auch mal ein Screenshot angehängt, sieht aus wie bei dir.. oder?

Allerdings passiert nichts, keine Fehlermeldung und Rechner geht nicht an.
(Mit einer anderen Software habe ich schon getestet ob es mit diesem Rechner überhaupt funktioniert.)

/edit

Wobei, bei dir steht ja nach dem WOL Protokoll ARP for 192.168.123.150 blabla, ist das der Rechner den du angeschaltet hast?

Bei mir steht das ja nciht so da.

divBy0 25. Jun 2008 09:56

Re: Wake on LAN Problem :-(
 
Das verstehe ich nicht, vergleich doch mal die beiden Pakete.
Da muss es dann ja einen Unterschied geben.

[EDIT] Das ARP-blabla hat damit nichts zu tun, das die SPS hier im Netzwerk... [/EDIT]

paritycheck 25. Jun 2008 10:28

Re: Wake on LAN Problem :-(
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hatte vor einiger Zeit auch mal ein solches Tool geschrieben. Ich hängs einfach mal dran, vielleicht kannst Du ja was damit anfangen.

Gruß
Michael

TimmA 1. Jul 2008 07:38

Re: Wake on LAN Problem :-(
 
danke dir, habs mitlerweile auch hinbekommen! :-)

eine frage noch, ich hätte gerne einen status angezeigt von dem rechner den ich "wecken" will. also ob er an ist oder aus. und das in einer grafik wiedergeben.
wie kann ich das am einfachsten realisieren? habe mich schon mal hier im forum umgeschaut ob man evtl. den rechner anpingen kann und das dann auswerten ob er antwortet oder nicht, oder geht das irgendwie viel einfacher?

rollstuhlfahrer 1. Jul 2008 08:59

Re: Wake on LAN Problem :-(
 
Anpingen könnte zu Problemen führen, wenn die Netzwerkkarte noch keine IP-Adresse hat, was leider der Standartzustand während des Bootens ist. Andere Lösungen als Warten fallen mir keine ein, außer du lötest dir einen Server den du an die Netzwerkkarte dranhängst. :mrgreen:

Bernhard

paritycheck 1. Jul 2008 11:45

Re: Wake on LAN Problem :-(
 
Hi,

Wenn es nur darum geht zu überprüfen ob ein Rechner im Netzwerk eingeschaltet ist oder nicht nehme ich meistens diese Funktion. Indys gehen auch aber z.B bei Konsolenanwendungen wird mir dann die Exe zu groß :stupid:

Delphi-Quellcode:
unit hostalive;

interface

function IsHostAlive(Hostname: String; pTripTime: PCardinal = nil; Timeout: Integer = 1000; TTL: Integer = 255): Boolean;

implementation

uses
  Windows,
  Winsock;

type
  IP_OPTION_INFORMATION = packed record
    TTL: byte;
    TOS: byte;
    Flags: byte;
    OptionsSize: byte;
    OptionsData: pchar;
  end;
  PIP_OPTION_INFORMATION = ^IP_OPTION_INFORMATION;

  ICMP_ECHO_REPLY = packed record
    Address: in_addr;
    Status: Cardinal;
    RoundTripTime: Cardinal;
    DataSize: word;
    Reserved: word;
    Data: pointer;
    Options: IP_OPTION_INFORMATION;
  end;
  PICMP_ECHO_REPLY = ^ICMP_ECHO_REPLY;

function IcmpCreateFile(): Cardinal; stdcall; external 'Iphlpapi.dll' name 'IcmpCreateFile';
function IcmpCloseHandle(IcmpHandle: Cardinal): Boolean; stdcall; external 'Iphlpapi.dll' name 'IcmpCloseHandle';
function IcmpSendEcho(IcmpHandle: Cardinal; DestinationAddress: Cardinal; RequestData: Pointer; RequestSize: Word; RequestOptions: PIP_OPTION_INFORMATION; ReplyBuffer: Pointer; ReplySize: Cardinal; Timeout: Cardinal): Cardinal; stdcall; external 'Iphlpapi.dll' name 'IcmpSendEcho';

function IsHostAlive(Hostname: String; pTripTime: PCardinal = nil; Timeout: Integer = 1000; TTL: Integer = 255): Boolean;
const
  SendBuffer: array[0..31] of char =
              ('p', 'i', 'n', 'g', 'p', 'o', 'n', 'g',
               'p', 'i', 'n', 'g', 'p', 'o', 'n', 'g',
               'p', 'i', 'n', 'g', 'p', 'o', 'n', 'g',
               'p', 'i', 'n', 'g', 'p', 'o', 'n', 'g');
var
  WSA: TWSADATA;
  Reply: PICMP_ECHO_REPLY;
  Addr: Integer;
  hIcmp: cardinal;
  Options: IP_OPTION_INFORMATION;

  function ResolveHost(Hostname: String): Integer;
  type
    PPInAddr= ^PInAddr;
  var
    HostInfo: PHostEnt;
    T: PPInAddr;
  begin
    t:= nil;
    Result:= inet_addr(PChar(Hostname));
    if result = INADDR_NONE then begin
       HostInfo:= gethostbyname(PChar(Hostname));
       if HostInfo <> nil then
          T:= Pointer(HostInfo^.h_addr_list);
       if (T <> nil) and (T^<> nil) then begin
          Result:= T^^.S_addr;
       end;
    end;
  end;

begin
  Result:= False;
  FillChar(Options, sizeof(IP_OPTION_INFORMATION), #0);
  Reply:= nil;
  options.TTL:= TTL;
  options.TOS:= 1;
  if WSAStartUp(((0 shl 8)+2), WSA) = 0 then begin
     Addr:= ResolveHost(Hostname);
     if Addr <> INADDR_NONE then begin
        hIcmp:= IcmpCreateFile();
        if hicmp <> INVALID_HANDLE_VALUE then try
           Reply:= AllocMem(sizeof(ICMP_ECHO_REPLY)+sizeof(SendBuffer));
           IcmpSendEcho(hIcmp, Addr, @SendBuffer[0], sizeof(SendBuffer), @Options, Reply, sizeof(ICMP_ECHO_REPLY)+sizeof(SendBuffer), timeout);
           Result:= (Reply^.Status = 0);
           if Result and (pTripTime <> nil) then
              pTripTime^:= Reply^.RoundTripTime;
        finally
           IcmpCloseHandle(hIcmp);
           if Reply <> nil then
              FreeMem(Reply);
           WSACleanup();
        end;
     end else begin
        WSACleanup();
       // Hostname konnte nicht aufgelöst werden.
     end;
  end else begin
       // Winsock konnte nicht gestartet werden.
  end;
end;

end.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  RTT:Cardinal;
begin
  if IsHostalive('google.de', @RTT) then
     showmessage(inttostr(RTT)+'ms');
end;

TimmA 1. Jul 2008 15:52

Re: Wake on LAN Problem :-(
 
wenn ich das programm 1zu1 kopiere kann ich nicht kompilieren, liegt das an unseren verschiedenen delphi versionen?

toms 1. Jul 2008 15:54

Re: Wake on LAN Problem :-(
 
Zitat:

Zitat von TimmA
wenn ich das programm 1zu1 kopiere kann ich nicht kompilieren, liegt das an unseren verschiedenen delphi versionen?

:glaskugel: gut möglich, wo erhältst du denn einen Fehler?

TimmA 1. Jul 2008 16:37

Re: Wake on LAN Problem :-(
 
also, wenn ich den code so kopiere und einen button auf meine form ziehen will kommt:

"Fehler im Modul Unit11: Deklaration der Klasse TForm1 fehlt oder ist fehlerhaft"

bekomme ich irgendwie nicht hin das einzufügen :-(

wenn ich ein neues Projekt einfüge steht da ja auch

type
TForm1 = class(TForm)

wenn ich die tform1 zu den anderen bei type schreibe funktioniert es nicht :-(

rollstuhlfahrer 1. Jul 2008 16:38

Re: Wake on LAN Problem :-(
 
Mach aus TForm1 mal TForm11

TimmA 1. Jul 2008 16:45

Re: Wake on LAN Problem :-(
 
Zitat:

[Fehler] Unit1.pas(14): Undefinierter Bezeichner: 'TForm'
[Fehler] Unit1.pas(17): '=' erwartet, aber Bezeichner 'public' gefunden
[Fehler] Unit1.pas(19): ';' erwartet, aber 'END' gefunden
[Warnung] Unit1.pas(30): Text hinter dem abschließenden 'END.' wird vom Compiler ignoriert
[Fehler] Unit1.pas(5): Ungenügende Forward- oder External-Deklaration: 'IsHostAlive'
[Fataler Fehler] Project2.dpr(5): Verwendete Unit 'Unit1.pas' kann nicht compiliert werden
das mit der 11 hab ich ausprobiert, was habe ich falsch gemacht? :-((

Delphi-Quellcode:

unit hostalive;

interface

function IsHostAlive(Hostname: String; pTripTime: PCardinal = nil; Timeout: Integer = 1000; TTL: Integer = 255): Boolean;

implementation

uses
  Windows,
  Winsock;

type
    TForm11 = class(TForm)
    IP_OPTION_INFORMATION = packed record
    TTL: byte;
    TOS: byte;
    Flags: byte;
    OptionsSize: byte;
    OptionsData: pchar;
  end;
  PIP_OPTION_INFORMATION = ^IP_OPTION_INFORMATION;

  ICMP_ECHO_REPLY = packed record
    Address: in_addr;
    Status: Cardinal;
    RoundTripTime: Cardinal;
    DataSize: word;
    Reserved: word;
    Data: pointer;
    Options: IP_OPTION_INFORMATION;
  end;
  PICMP_ECHO_REPLY = ^ICMP_ECHO_REPLY;

function IcmpCreateFile(): Cardinal; stdcall; external 'Iphlpapi.dll' name 'IcmpCreateFile';
function IcmpCloseHandle(IcmpHandle: Cardinal): Boolean; stdcall; external 'Iphlpapi.dll' name 'IcmpCloseHandle';
function IcmpSendEcho(IcmpHandle: Cardinal; DestinationAddress: Cardinal; RequestData: Pointer; RequestSize: Word; RequestOptions: PIP_OPTION_INFORMATION; ReplyBuffer: Pointer; ReplySize: Cardinal; Timeout: Cardinal): Cardinal; stdcall; external 'Iphlpapi.dll' name 'IcmpSendEcho';

function IsHostAlive(Hostname: String; pTripTime: PCardinal = nil; Timeout: Integer = 1000; TTL: Integer = 255): Boolean;
const
  SendBuffer: array[0..31] of char =
              ('p', 'i', 'n', 'g', 'p', 'o', 'n', 'g',
               'p', 'i', 'n', 'g', 'p', 'o', 'n', 'g',
               'p', 'i', 'n', 'g', 'p', 'o', 'n', 'g',
               'p', 'i', 'n', 'g', 'p', 'o', 'n', 'g');
var
  WSA: TWSADATA;
  Reply: PICMP_ECHO_REPLY;
  Addr: Integer;
  hIcmp: cardinal;
  Options: IP_OPTION_INFORMATION;

  function ResolveHost(Hostname: String): Integer;
  type
    PPInAddr= ^PInAddr;
  var
    HostInfo: PHostEnt;
    T: PPInAddr;
  begin
    t:= nil;
    Result:= inet_addr(PChar(Hostname));
    if result = INADDR_NONE then begin
       HostInfo:= gethostbyname(PChar(Hostname));
       if HostInfo <> nil then
          T:= Pointer(HostInfo^.h_addr_list);
       if (T <> nil) and (T^<> nil) then begin
          Result:= T^^.S_addr;
       end;
    end;
  end;

begin
  Result:= False;
  FillChar(Options, sizeof(IP_OPTION_INFORMATION), #0);
  Reply:= nil;
  options.TTL:= TTL;
  options.TOS:= 1;
  if WSAStartUp(((0 shl 8)+2), WSA) = 0 then begin
     Addr:= ResolveHost(Hostname);
     if Addr <> INADDR_NONE then begin
        hIcmp:= IcmpCreateFile();
        if hicmp <> INVALID_HANDLE_VALUE then try
           Reply:= AllocMem(sizeof(ICMP_ECHO_REPLY)+sizeof(SendBuffer));
           IcmpSendEcho(hIcmp, Addr, @SendBuffer[0], sizeof(SendBuffer), @Options, Reply, sizeof(ICMP_ECHO_REPLY)+sizeof(SendBuffer), timeout);
           Result:= (Reply^.Status = 0);
           if Result and (pTripTime <> nil) then
              pTripTime^:= Reply^.RoundTripTime;
        finally
           IcmpCloseHandle(hIcmp);
           if Reply <> nil then
              FreeMem(Reply, sizeof(ICMP_ECHO_REPLY)+8);
           WSACleanup();
        end;
     end else begin
        WSACleanup();
       // Hostname konnte nicht aufgelöst werden.
     end;
  end else begin
       // Winsock konnte nicht gestartet werden.
  end;
end;

end.

rollstuhlfahrer 1. Jul 2008 16:50

Re: Wake on LAN Problem :-(
 
omg

code:

CODE

unit hostalive;

interface

function IsHostAlive(Hostname: String; pTripTime: PCardinal = nil; Timeout: Integer = 1000; TTL: Integer = 255): Boolean;

implementation

uses
Windows,
Winsock;

type
TForm11 = class(TForm) // *wegstreich*
IP_OPTION_INFORMATION = packed record
TTL: byte;
TOS: byte;
Flags: byte;
OptionsSize: byte;
OptionsData: pchar;
end;

(SNIP)


Den ganzen "Mist" speicherst du als eigenständige Unit (.pas-Datei). Dann fügst du die Datei an dein Projekt an (über das Oderner-mit-Plus-Symbol). Nun fügst du in der entsprechenden Unit (da wo du das verwenden willst) den bezeichner "hostalive" (o.ä. hauptsache den Namen der Unit) in die Uses-Liste.
Dann mal weitersehen.

Bernhard

EDIT: Falls du grad ein wenig Zeit hast, bleib online. Ich versuch so schnell wie es geht zu antworten

paritycheck 1. Jul 2008 16:57

Re: Wake on LAN Problem :-(
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das liegt daran dass es kein eigenständiges programm sondern eine unit ist. Speicher das ganze mal als hostalive.pas im projektverzeichnis ab und binde es dann per uses im Projekt ein.

Hab dir mal ne kleine Demo angehängt.

rollstuhlfahrer 1. Jul 2008 17:00

Re: Wake on LAN Problem :-(
 
Für Delphi7 musst du entweder die Unit SysUtils in die Unit hostalive einbinden oder folgende Funktion unterhalb von implementation einfügen:

Delphi-Quellcode:
{ Memory management routines }  // kommt aus SysUtils

function AllocMem(Size: Cardinal): Pointer;
begin
  GetMem(Result, Size);
  FillChar(Result^, Size, 0);
end;
Bernhard

EDIT: Ich machs mal genauer:

Zwischen
"function IcmpSendEcho(IcmpHandle: Cardinal; DestinationAddress: Cardinal; RequestData: Pointer; RequestSize: Word; RequestOptions: PIP_OPTION_INFORMATION; ReplyBuffer: Pointer; ReplySize: Cardinal; Timeout: Cardinal): Cardinal; stdcall; external 'Iphlpapi.dll' name 'IcmpSendEcho';"

und (also hier; etwa Zeile 40)

"function IsHostAlive(Hostname: String; pTripTime: PCardinal = nil; Timeout: Integer = 1000; TTL: Integer = 255): Boolean; "

TimmA 1. Jul 2008 17:12

Re: Wake on LAN Problem :-(
 
danke euch, meine signatur ist halt nicht ganz unberechtigt ;-)

wenn ich die demo runterlade und das projekt öffne und starten will kommt


Zitat:

[Warnung] hostalive.pas(19): Unsicherer Typ 'PChar'
[Warnung] hostalive.pas(29): Unsicherer Typ 'Pointer'
[Warnung] hostalive.pas(36): Unsicherer Typ 'Pointer'
[Warnung] hostalive.pas(36): Unsicherer Typ 'Pointer'
[Warnung] hostalive.pas(60): Unsicherer Typ 'PChar'
[Warnung] hostalive.pas(62): Unsicherer Typ 'PChar'
[Warnung] hostalive.pas(64): Unsicherer Typ 'Pointer'
[Fehler] hostalive.pas(82): Undefinierter Bezeichner: 'AllocMem'
[Warnung] hostalive.pas(83): Unsicherer Code '@ operator'
[Warnung] hostalive.pas(83): Unsicherer Code '@ operator'
[Warnung] hostalive.pas(90): Unsicherer Code 'FreeMem'
[Fataler Fehler] frmDemo.pas(7): Verwendete Unit 'hostalive.pas' kann nicht compiliert werden
unsicherer typ? :-(


sorry für meine späte antwort :oops:

rollstuhlfahrer 1. Jul 2008 17:15

Re: Wake on LAN Problem :-(
 
AllocMem oder SysUtils sind noch nicht hinzugefügt. Bei mir kommen die "unsichere Typ"-Meldungen nicht, da sie abschaltbar sind. Was an einem Pointer unsicher sein soll, weiß ich nicht. Desweiteren kannst du alle Warnungen ignorieren. Fehler mussen aber behoben werden.

Bernhard

Apollonius 1. Jul 2008 17:19

Re: Wake on LAN Problem :-(
 
Zitat:

Bei mir kommen die "unsichere Typ"-Meldungen nicht, da sie abschaltbar sind
Wohl eher, da du keine Delphi-.NET-Anwendung verwendest.

paritycheck 1. Jul 2008 17:21

Re: Wake on LAN Problem :-(
 
Liste der Anhänge anzeigen (Anzahl: 1)
Versuchs mal mit folgender Datei, damit sollte das ganze auch unter delphi 7 kompilieren.

TimmA 1. Jul 2008 17:25

Re: Wake on LAN Problem :-(
 
das geht, danke euch :-D

PeterPanino 28. Feb 2015 16:04

AW: Re: Wake on LAN Problem :-(
 
Zitat:

Zitat von paritycheck (Beitrag 798078)
Hi,

Wenn es nur darum geht zu überprüfen ob ein Rechner im Netzwerk eingeschaltet ist oder nicht nehme ich meistens diese Funktion. Indys gehen auch aber z.B bei Konsolenanwendungen wird mir dann die Exe zu groß :stupid:

Delphi-Quellcode:
unit hostalive;

...

Bei Domains gibt IsHostalive('delphipraxis.net', @RTT) immer False zurück, auch wenn die Domain de facto normal erreichbar ist. WARUM?

Bei IP-Adressen gibt IsHostalive('88.198.53.15', @RTT) immer True zurück, auch wenn das Kabel vom DSL-Router abgezogen ist. WARUM?


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