Entwickler-Ecke

Windows API - Internet-Zeit


Burgpflanze - Mi 08.01.03 12:27
Titel: Internet-Zeit
Wenn ich zu einem Time-Server auf Port 37 connecte, bekomme ich als Antwort einen 4 Byte langen Wert, den ich mittels

Quelltext
1:
error := recv(sock_handle, ut, 4, 0);                    

in eine Variable (ut) vom Typ Cardinal einlese.

Mein Problem ist nun, wie ich diesen Wert in die Systemzeit (_SYSTEMTIME) umrechnen muss, damit ich meine PC-Uhr mit der Internet-Zeit synchronisieren kann, und das ohne VCL, womit also auch die IdTime-Komponente ausscheidet.

Wer weiß, wie es gemacht wird? Mir helfen leider nicht die vielen Code-Beispiele in C, die ich im Internet gefunden habe :?

Vielen Dank schon mal.


Gruss, Burgpflanze


matze - Mi 08.01.03 18:26

du kannst die indy komoos doch auch hernehmen, wenn du nonvcl codest !!! lies dir ambesten mal die tuts auf http://www.luckie-online.de durch. da wird beschrieben, wie man kompos auch bei nonvcl hernimmt


Delete - Mi 08.01.03 18:43

matze hat folgendes geschrieben:
du kannst die indy komoos doch auch hernehmen, wenn du nonvcl codest !!! lies dir ambesten mal die tuts auf http://www.luckie-online.de durch. da wird beschrieben, wie man kompos auch bei nonvcl hernimmt

:shock: Wo?


matze - Mi 08.01.03 18:55

war das nicht bei dir ???? mist


Delete - Mi 08.01.03 18:58

Nicht das ich wüßte.

Aber probier mal etwas mit TSYSTEMTIME und TFILETIME rum. Das BVuch, wo ich es drin stehen habe, hab eich leider zu Hause und jetzt nicht hier griff bereit.

Und poste mal die Links zu den C-Beispielen, dan kann man sich das mal ankucken.


matze - Mi 08.01.03 19:12

aber mann kann doch auch VCL kompos beim nonvcl coden hernehmen oder ??


Delete - Mi 08.01.03 19:21

Wie? Was für ein Objekt willst du als Parent oder Owner angeben? Du hast ja gerade kein Objekt TForm. Das ist ja gerade der Gag. das einzigste, was gehen würde, du schreibst die Kompo zu einer Unit um. Ist aber viel Arbeit und eventuell nicht immer zu realisieren.


matze - Mi 08.01.03 21:17

dann ist das ja nicht wirklich komfortabel !!!


Delete - Mi 08.01.03 21:20

nonVCL = Handarbeit.
VCL = Klickibunti.

:mrgreen:


matze - Mi 08.01.03 21:24

also luckie: damit wir hier nicht das topic vollabern und das eigendliche thema verfehlen: http://www.auq.de/viewtopic.php?p=28522#28522


Delete - Mi 08.01.03 21:38

Wenn es sich meldet und die entsprechenden Links postet, dann kann man ihm auch weiterhelfen.


Burgpflanze - Do 09.01.03 15:19

Hab Lösung gefunden 8)


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
// Nur WinNT 3.5 und höher, Win2000 und WinXP, 
// da nur diese Versionen intern mit GMT-Zeit arbeiten,
// ansonsten muss die Zeitzone berücksichtig werden
function SetTimeFromInternet(buf: array of Char): Integer;
var
  umt: Int64;
  ft: _FILETIME;
  st: _SYSTEMTIME;
  li: ULARGE_INTEGER;
begin
  Result := 0;

  umt := Ord(buf[0]) * 256 * 256 * 256 + Ord(buf[1]) * 256 * 256 +
      Ord(buf[2]) * 256 + Ord(buf[3]);

  st.wYear := 1900;
  st.wMonth := 1;
  st.wDayOfWeek := 0;
  st.wDay := 1;
  st.wHour := 0;
  st.wMinute := 0;
  st.wSecond := 0;
  st.wMilliseconds := 0;

  if not SystemTimeToFileTime(st, ft) then
  begin
    Result := GetLastError;
    Exit;
  end;

  li.QuadPart := umt * 10000000;
  li.QuadPart := li.QuadPart + ULARGE_INTEGER(ft).QuadPart;

  if not FileTimeToSystemTime(_FILETIME(li), st) then
  begin
    Result := GetLastError;
    Exit;
  end;

  if not SetSystemTime(st) then Result := GetLastError;
end;


Aber trotzdem danke!

Gruss, Burgpflanze


Delete - Do 09.01.03 17:23

Puh:

Quelltext
1:
2:
umt := Ord(buf[0]) * 256 * 256 * 256 + Ord(buf[1]) * 256 * 256 +
  Ord(buf[2]) * 256 + Ord(buf[3]);

:?

Wäre es nicht a) besser, die vier Bytes gleich als solche zu übergeben, und b) sinnvolle Funktionen des Systems zu nutzen? bspw:

Quelltext
1:
umt := MAKELONG(MAKEWORD(buf[3],buf[2]),MAKEWORD(buf[1],buf[0]));                    

Das Ergebnis wäre das gleiche. Die Sache sieht allerdings gefälliger aus, und da die Funktionen Teil der Windows-Unit sind, spricht doch auch nichts gegen ihre Verwendung. :wink:

Warum ist diese "Umwandlung" eigentlich erforderlich? Hm, vielleicht sollte ich mir das Protokoll und ein paar Beispiele mal ansehen, damit ich das nachvollziehen kann ...


Burgpflanze - Fr 10.01.03 16:47

Hallo Matthias,

so wie du es machen würdest, geht es aber nicht,
zumal du ein Char nicht als Byte übergeben kannst :wink:

Das Ergebnis ist auch nicht dasselbe.

Aber so geht es auch:

Quelltext
1:
umt := Ord(buf[0]) shl 24 + Ord(buf[1]) shl 16 + Ord(buf[2]) shl 8 + Ord(buf[0]);                    


Gruss, Burgpflanze


Delete - Fr 10.01.03 19:30

*hi hi* Du hast Punkt A vergessen:
MathiasSimmack hat folgendes geschrieben:
Wäre es nicht a) besser, die vier Bytes gleich als solche zu übergeben, ...

Unter der Maßgabe, der Puffer wäre also kein "array of char" sondern ein "array of byte", habe ich die Funktionen MAKELONG/MAKEWORD benutzt. Und bei allen Versuchen waren die Ergebnisse mit deiner Methode und mit meinem Weg irgendwie immer identisch.

Wann unterscheiden sich die Ergebnisse?
Und noch mal: warum diese Trennung in 4 einzelne Bytes (ausgehend von der Vermutung, dass es sich dabei um den 4-Byte-Wert des Time-Servers handelt) und "Drehung"?

Ja ja, ich bin neugierig ... :wink:


Burgpflanze - Fr 10.01.03 20:34

Ich muss dir leider widersprechen - die Ergebnisse sind nicht gleich - warum auch immer :(

Und nun zu meiner Vorgehensweise:

- Connect zu einem Zeitserver (ich nehme ntpserv.fh-magdeburg.de, weil
dieser nur 30 km von mir entfernt ist, es geht aber auch jeder andere,
wenn er über Port 37 zu erreichen ist)

- Dann lese ich die Antwort auf den Connect aus:

Quelltext
1:
2:
3:
var buf: array[0..3] of Byte; // Nicht lachen jetzt

error := recv(socket_handle, buf, 4, 0);


Theoretisch kann man auch eine Integer-Variable als Buffer verwenden,
jedoch stimmt dann das Ergebnis überhaupt nicht mehr, auch wenn man,
wie in den von mir gefundenen C-Beispielen gemacht, folgendes macht:

Quelltext
1:
2:
3:
4:
var buf: Integer;

error := recv(socket_handle, buf, 4, 0);
buf := htonl(buf);


Das von mir zur Zeit eingesetzte Verfahren ist eine Kombination aus
einem VB-Beispiel und einem C-Beispiel und funktioniert.

Warum nun aber dieser Byte-Dreher gemacht werden muss?

Die Antwort des Servers kommt in "host byte order" und muss in "TCP/IP network byte order" umgerechnet werden.

Leider kann ich dir nicht mehr dazu sagen, da ich ganz sicher kein
Spezialist des NTP-Protokolls bin :D


Bis demnächst,
Burgpflanze


Delete - Fr 10.01.03 22:13

Ich habe mir gerade mal fix ein Mini-Tool geschrieben, das sich zweimal mit dem Server verbindet und die Zeit holt. Einmal als Integer und einmal als Byte-Array. "Drehe" ich die Integer-Variable mit htonl und lasse mir beides (hexadezimal) in zwei Edits anzeigen, ist´s der selbe Wert wie das Byte-Array.

Übergebe ich die Integer-Variable aber an deine Funktion, "SetTimeFromInternet" (die mir aber nicht die Zeit verstellt, sondern die ermittelte Zeit in einem dritten Edit darstellt), kommt irgendwas als Ergebnis; nicht jedoch die tatsächliche Uhrzeit. Ich habe natürlich diese Zeile

Quelltext
1:
li.QuadPart := umt * 10000000;                    

geändert, da die Int64-Variable mit dem eigentlich korrekten Wert bereits im Funktionskopf angegeben wird.

Hm ... :?
Ich denke, ich habe bloß was übersehen; denn logisch betrachtet sollte es gehen. Der Wert ist ja der selbe ...


Burgpflanze - Fr 10.01.03 22:27

Du kannst mir deinen Code ja mal schicken, entweder hier als Posting oder per e-Mail.

Dieser Multiplikator (10000000) scheint aber notwendig zu sein, zumindest
war er in allen C-Beispielen vorhanden.

Gruss, Burgpflanze


Delete - Sa 11.01.03 13:42

Jetzt geht´s auch mit Cardinal. Merkwürdig ... Also, gut. Kurz zum Programm: es ist ein NonVCL-Dialog mit vier Edits:

Quelltext
1:
2:
3:
4:
5:
const
  IDC_BYTEARRAY  = 110;
  IDC_CARDINAL   = 111;
  IDC_BYTEMEANS  = 112;
  IDC_CARDMEANS  = 113;

Ein Timer wird jede Sekunde aktiv:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
    WM_TIMER:
      if(wp = IDC_TIMER) then begin
        hostent := gethostbyname('ntpserv.fh-magdeburg.de');

        // als Byte-Array lesen
        s       := socket(PF_INET,SOCK_STREAM,0);
        if(s <> INVALID_SOCKET) and (hostent <> nil) then begin
          SetLength(b,4);

          ZeroMemory(@saddr,sizeof(TSockAddr));
          saddr.sin_addr.S_addr := integer(pointer(hostent^.h_addr_list^)^);
          saddr.sin_family      := PF_INET;
          saddr.sin_port        := htons(37);

          res                   := connect(s,saddr,sizeof(TSockAddr));
          if(res <> SOCKET_ERROR) then
            res                 := recv(s,b[0],length(b),0);

          // Byte-Array anzeigen, ...
          if(res <> SOCKET_ERROR) then
            SetWindowText(GetDlgItem(hwndDlg,IDC_BYTEARRAY),
            pchar(Format('%.2x %.2x %.2x %.2x',[b[0],b[1],b[2],b[3]])));

          // ... & Zeit berechnen
          SetTimeFromInternet(@b,nil,GetDlgItem(hwndDlg,IDC_BYTEMEANS));
          SetLength(b,0);

          CloseSocket(s);
        end;

        // als Cardinal lesen
        s       := socket(PF_INET,SOCK_STREAM,0);
        if(s <> INVALID_SOCKET) and (hostent <> nil) then begin
          ZeroMemory(@saddr,sizeof(TSockAddr));
          saddr.sin_addr.S_addr := integer(pointer(hostent^.h_addr_list^)^);
          saddr.sin_family      := PF_INET;
          saddr.sin_port        := htons(37);

          res                   := connect(s,saddr,sizeof(TSockAddr));
          if(res <> SOCKET_ERROR) then
            res                 := recv(s,i,sizeof(i),0);

          if(res <> SOCKET_ERROR) then
            // Cardinal-Wert "drehen" (host byte order -> TCP/IP network byte order)
            i                   := htonl(i)
          else
            i                   := 0;

          // Cardinal als 8-stelligen Hex-Wert anzeigen, ...
          if(res <> SOCKET_ERROR) then
            SetWindowText(GetDlgItem(hwndDlg,IDC_CARDINAL),
            pchar(Format('0x%.8x',[i])));

          // ... & Zeit berechnen
          SetTimeFromInternet(nil,@i,GetDlgItem(hwndDlg,IDC_CARDMEANS));

          CloseSocket(s);
        end;

Die Variablen fix:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
type
  TBArray = array of byte;
  PBArray = ^TBArray;
var
  hostent   : PHostEnt;
  s         : TSocket;
  saddr     : TSockAddr;
  res       : integer;
  b         : TBArray;
  i         : cardinal;

Und deine umgeschriebene Funktion, die mir nur die Zeit anzeigt aber nicht verstellt:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
procedure SetTimeFromInternet(b: PBArray; i: PDWORD; wnd: HWND);
var
  umt : int64;
  st  : TSystemTime;
  ft  : TFileTime;
  li  : ULARGE_INTEGER;
  buf : array[0..MAX_PATH]of char;
begin
  if(b = nil) and (i = nil) then exit;

  if(i = nil) then umt := b^[0] shl 24 +
                          b^[1] shl 16 +
                          b^[2] shl 8  +
                          b^[3]
  else umt := i^;

  st.wYear         := 1970;
  st.wMonth        := 1;
  st.wDayOfWeek    := 0;
  st.wDay          := 1;
  st.wHour         := 0;
  st.wMinute       := 0;
  st.wSecond       := 0;
  st.wMilliseconds := 0;
  if(not SystemTimeToFileTime(st,ft)) then exit;

  li.QuadPart      := (umt * 10000000) + ULARGE_INTEGER(ft).QuadPart;
  if(not FileTimeToSystemTime(TFileTime(li),st)) then exit;

  ZeroMemory(@buf,sizeof(buf));
  if(GetTimeFormat(LOCALE_USER_DEFAULT,
    TIME_FORCE24HOURFORMAT,
    @st,
    nil,
    buf,
    sizeof(buf)) > 0) then SetWindowText(wnd,buf);
end;

Ich habe mich für Zeiger entschieden, weil die Prüfung so einfacher ist. Da "b" ja ein Array ist, kann man (IMHO?) nicht einfach

Quelltext
1:
if b = 0                    

prüfen.


So, nun frag mich aber bitte nicht, was ich gestern falsch gemacht habe ... Ich weiß es nicht ... :?

Ach ja: Wer´s probieren will - "WsaStartup" und "WsaCleanup" nicht vergessen. Auf Wunsch kann ich aber auch gern das Ding hochladen; daran soll´s nicht scheitern.


Delete - Sa 11.01.03 16:25

Ja, lad das bitte mal hoch, das will ich mir mal ansehen.


Delete - Sa 11.01.03 20:27

Schon oben. ´s lagert hier [http://www.reihe5.de/WebTime.zip] (4,23k). Ist nur der Quellcode; ich denke: Delphi-Versions unabhängig; für Nicht-Visual Studio-Besitzer (ich erstelle die Dialogressourcen damit!) liegt eine "dialog.NoVS.rc" bei.

btw: Ich bin ein bisschen unsicher wg. dieser Zeile:

Quelltext
1:
st.wYear := 1970;                    

Bei Burgpflanze steht im Code (s. erste Seite) "1900", aber die ganzen Infos zum Protokoll beziehen sich auf die abgelaufenen Sekunden seit dem 1. Januar 1970, Null Uhr. Wie dem auch sei - auf die Zeit hat´s keinen Einfluss. Ich lasse das Ding gerade laufen, und es wird mir auch 18 Uhr 31 (UTC) angezeigt.


Delete - Sa 11.01.03 22:56

Wenn ich da 1900 eintrage dann stimmt auch das Datum. Im laufe des Abends wird von mir noch ein Programm kommen um dann die Systemzeit mit dem Zeitserver abzugleichen.

Kennt in diesem Zusammenhang jemand eine Liste mit zeitservern? Einer kann ja mal down sein.

Hier mal der aktuelle Stand der Dinge (noch ohne Soße, da noch nicht fertig): INetTime [http://www.luckie-online.de/cgi-bin/load.cgi?downloads/inettime.exe]

Ungepackte Exe da nonVCL. :wink:


Delete - So 12.01.03 09:47

Zitat:
Wenn ich da 1900 eintrage dann stimmt auch das Datum.

Ja, das habe ich auch gemerkt. Nun wissen wir auch, warum 1900 da stehen muss ...

Zitat:
Im laufe des Abends wird von mir noch ein Programm kommen um dann die Systemzeit mit dem Zeitserver abzugleichen.

Irgendwie habe ich genau das ... äh ... befürchtet ... :wink:

Zitat:
Kennt in diesem Zusammenhang jemand eine Liste mit zeitservern?

Nein. Aber ich hoffe, du machst es von Anfang an so, dass alle Zeitserver in einer externen INI liegen. Dann kann der Anwender deine Vorgaben rausschmeißen und eigene benutzen, oder eigene hinzufügen, usw.


Delete - So 12.01.03 16:16

MathiasSimmack hat folgendes geschrieben:
Bei Burgpflanze steht im Code (s. erste Seite) "1900", aber die ganzen Infos zum Protokoll beziehen sich auf die abgelaufenen Sekunden seit dem 1. Januar 1970, Null Uhr.

Sorry, mein Fehler. Im Time Protocol [http://www.faqs.org/rfcs/rfc868.html] heißt es ganz klar:
Zitat:
The time is the number of seconds since 00:00 (midnight) 1 January 1900 GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this base will serve until the year 2036.


Delete - So 12.01.03 17:35

MathiasSimmack hat folgendes geschrieben:
Aber ich hoffe, du machst es von Anfang an so, dass alle Zeitserver in einer externen INI liegen. Dann kann der Anwender deine Vorgaben rausschmeißen und eigene benutzen, oder eigene hinzufügen, usw.

Tztztz, was denkst du von mir? :cry:


Delete - So 12.01.03 18:46

Es war ja nur ein Gedanke, Luckie. Anhand der Exe kann man ja nicht sehen, ob da schon INI-Funktionalität drin ist ... Ich hab´s mal ausprobiert für das DateTime-Beispiel aus den Tutorials.

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
//
// Liste mit den Zeitservern aus der INI-Datei lesen
//
const
  szDateTimeIni = 'DateTime.ini';
  szIniKey      = 'serverlist';
  BUFSIZE       = 16348;

procedure LoadTimeServers(hCombobox: HWND);
var
  buf, p        : pchar;
  kl            : array of string;
  i             : integer;
begin
  // Inhalt der Combobox leeren
  SendMessage(hCombobox,CB_RESETCONTENT,0,0);

  // Topicnamen aus der INI lesen
  GetMem(buf,BUFSIZE);
  try
    SetLength(kl,0);
    if(GetPrivateProfileString(szIniKey,nil,nil,buf,BUFSIZE,
      pchar(ExtractFilePath(paramstr(0)) + szDateTimeIni)) <> 0) then
    begin
      p := buf;
      while(p^ <> #0) do begin
        SetLength(kl,length(kl)+1);
        kl[length(kl)-1] := p;

        inc(p,strlen(p)+1);
      end;
    end;
  finally
    FreeMem(buf,BUFSIZE);
  end;

  // Werte aus der INI lesen, & in die Combobox eintragen
  if(length(kl) > 0) then begin
    GetMem(buf,BUFSIZE);
    try
      for i := 0 to length(kl)-1 do begin
        ZeroMemory(buf,BUFSIZE);
        if(GetPrivateProfileString(szIniKey,@kl[i][1],nil,
          buf,BUFSIZE,pchar(ExtractFilePath(paramstr(0)) + szDateTimeIni)) <> 0) then

        SendMessage(hCombobox,CB_ADDSTRING,0,LPARAM(buf));
      end;
    finally
      FreeMem(buf,BUFSIZE);
    end;

    SetLength(kl,0);
  end;

  // Eintrag auswählen, wenn vorhanden
  if(SendMessage(hCombobox,CB_GETCOUNT,0,0) > 0) then
    SendMessage(hCombobox,CB_SETCURSEL,0,0);
end;

Ein paar Server, die ich noch so gefunden habe:

Quelltext
1:
2:
3:
4:
5:
[serverlist]
svr1=ntpserv.fh-magdeburg.de
svr2=ntps1-0.cs.tu-berlin.de
svr3=ntps1-1.cs.tu-berlin.de
svr4=ntps1-1.uni-erlangen.de

Allerdings hab´ ich´s mir verkniffen, jede Sekunde zu checken. Da leidet die Performance. Ein Buttonklick wäre sinnvoller.

Ach ja, als Tipp für dein Programm: bitte nicht selbst wählen lassen! Ich würde prüfen, ob eine Verbindung besteht, und dann anbieten, die Zeit von einem Server zu holen, usw.
Mir gefällt´s nämlich nicht, wenn sich jedes itsy-bitsy Programm ins Web wählt. Ist aber nur meine Meinung. :)

So, bleibt nur noch die Frage: was bedeutet der Multiplikator "10.000.000"? Warum gerade 10Mio? Bzw. was bedeutet dieser Wert?
Wer mir das erklärt, wird von mir namentlich im Update des DateTime-Beitrags von Luckies Tutorials erwähnt ... :wink:

Hm, is´ wahrscheinlich kein Anreiz? :twisted:


Delete - So 12.01.03 20:32

So hier ist es: http://www.auq.de/viewtopic.php?t=5857

Es wählt sich nur leider selber ein. mal sehen, was sich da machen läßt. :wink:
Aber in einem extra Thread checken, ob eine Verbindung betseht, halte ich für etwas übertrieben.


Burgpflanze - So 12.01.03 21:18

Unter den folgenden Links findet ihr eine ganze Reihe von
Zeitservern aus aller Welt:
http://www.eecis.udel.edu/~mills/ntp/clock1a.html
http://www.eecis.udel.edu/~mills/ntp/clock2a.html

Die beiden wichtigsten deutschen sind:
ptbtime1.ptb.de und ptbtime2.ptb.de .
(Beide Physikalisch-technische Universität Braunschweig)


Gruss, Burgpflanze


Delete - So 12.01.03 22:15

Luckie hat folgendes geschrieben:
Aber in einem extra Thread checken, ob eine Verbindung betseht, halte ich für etwas übertrieben.

Wie: extra Thread? Da ich im genannten DateTime-Beispiel aus den Tutorials einen 1sec-Timer habe (der ja die lokale und UTC-Zeit im System liest und anzeigt), spricht nichts dagegen, in dieser WM_TIMER-Abfrage mit InternetGetConnectedState den Web-Status zu prüfen und den Button für die Server-Zeit entsprechend freizuschalten ... Ach was red´ ich; ich bastel noch ein bisserl am Quellcode rum, dann schick´ ich´s dir einfach mal. :)


Burgpflanze - Mo 13.01.03 05:39

@Matthias

Oder benutze ein asynchrones socket, dann brauchst du das nicht in
einen extra Thread packen :wink:

@Luckie

Das einzigste, was ich bisher zu "10.000.000" in Erfahrung bringen konnte:
- Dieser Wert steht für die Anzahl von 100-Nanosekunden-Intervallen pro Sekunde
(1 sec = 1.000 millisec = 1.000.000 microsec = 10.000.000 100-nanosec-Intervalle)

@All

Und hier meine überarbeitete Funktion - nun wird auch die Zeitzone berücksichtigt:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
// time ist schon der "gedrehte" Wert
procedure SyncTime(time: Cardinal);
const
  SYSTEM_SECONDS = 10000000;
var
  bias: Integer;
  ft: TFileTime;
  st: TSystemTime;
  li: TULargeInteger;
  tz: TTimeZoneInformation;
begin
  st.wYear := 1900;
  st.wMonth := 1;
  st.wDayOfWeek := 0;
  st.wDay := 1;
  st.wHour := 0;
  st.wMinute := 0;
  st.wSecond := 0;
  st.wMilliseconds := 0;

  if not SystemTimeToFileTime(st, ft) then Exit;

  case GetTimeZoneInformation(tz) of
    TIME_ZONE_ID_DAYLIGHT: bias := tz.Bias + tz.DaylightBias;
    TIME_ZONE_ID_STANDARD: bias := tz.Bias + tz.StandardBias;
    TIME_ZONE_ID_UNKNOWN: bias := 0;
  else
    Exit;
  end;
  bias := -bias;

  li.QuadPart := Int64(time) * SYSTEM_SECONDS + Int64(bias * 60) * SYSTEM_SECONDS;
  li.QuadPart := li.QuadPart + TULargeInteger(ft).QuadPart;

  if not FileTimeToSystemTime(TFileTime(li), st) then Exit;

  SetLocalTime(st);
  SendMessage(HWND_BROADCAST, WM_TIMECHANGE, 0, 0);
end;


Mfg Burgpflanze


(PS: Vielleicht erwähnt mich Luckie auch in seinem iTime :wink: )