Durch exakte Uhrzeit aus dem Internet die Systemuhr stellen lassen



  • Hi,
    ich möchte ein Programm schreiben, das
    1. sich aus dem Internet die aktuelle Uhrzeit holt und
    2. die Systemzeit aktualisiert.
    Ich weiß bloß nicht, wie ich Punkt 1 realisieren soll. Kann mir da einer helfen?



  • WebFritzi schrieb:

    Hi,
    ich möchte ein Programm schreiben, das
    1. sich aus dem Internet die aktuelle Uhrzeit holt und
    2. die Systemzeit aktualisiert.
    Ich weiß bloß nicht, wie ich Punkt 1 realisieren soll. Kann mir da einer helfen?

    Hast Du den Petzold, da wird so ein Programm erstellt. Falls nicht dann google mal nach Time Protocol (RFC 868).

    Ich poste mal hier wie der Ablauf in Petzold beschrieben ist:

    1. Eine Verbindung mit Port 37 eines Servers herstellen, der diesen Dienst unterstützt
    2. Auf einen 32-Bit-Wert warten, der die Zahl der seit dem 1.1.1900 um 0:00:00 Uhr verstrichene Sekunden angibt.
    3. Die Verbindung beenden.



  • bevor du anfängst solltest du einen server finden der die richtige zeit anbietet.



  • Aha, mhm... Ich werds mal probieren...



  • Riskiere doch mal eine Blick auf http://www.ntp.org/ ! 😉

    Ich weiß zwar nicht ob es ntptimeset, ntpd und Konsorten auch für Windows gibt, aber die protokollspezifischen Sachen kannst Du auf alle Fälle übernehmen bzw. viel von ihnen lernen...



  • Alternativ geht auch Port 13, aber da kommt ein String zurück. Zum Beispiel so (in Java):

    import java.net.*;
    import java.io.*;
    
    public class Daytime
    {
       public static void main(String[] args)
       {
          try
          {
             Socket socket = new Socket ("www.uni-hamburg.de",13);
             InputStream stream = socket.getInputStream();
             int len;
             byte [] bytes = new byte [50];
             while ((len = stream.read(bytes)) != -1)
             {
                System.out.write(bytes,0,len);
             }
             stream.close();
             socket.close();
             System.out.println();
          }
          catch (IOException e)
          {
             System.out.println (e);
          }
       }
    }
    

    Ausgabe:

    Thu Aug 7 23:39:06 2003

    Klappt aber wie gesagt nicht mit jedem Host. Dieses Programm terminiert nichtmal, wenn du es mit einem falschen Host versuchst.



  • Mal eine ganz dumme Frage: Hat nicht sogar Windows mittlerweile einen eigenen NTP-Client an Board? Das ist nämlich eine technisch weit sauberere Lösung als diese daytime-Geschichte...



  • Naja, meine Synchronisation soll garnicht sooo genau sein. Ein paar Sekunden dürfen ruhig flöten gehen. Und alle Server (z.B. alle auf http://www.eecis.udel.edu/~mills/ntp/clock1a.html) geben die Zahl der seit dem 1.1.1900 um 0:00:00 Uhr verstrichenen Sekunden zurück, wenn man sie auf Port 37 anspricht, ja?



  • WebFritzi schrieb:

    Naja, meine Synchronisation soll garnicht sooo genau sein. Ein paar Sekunden dürfen ruhig flöten gehen.

    Dann brauchst Du nicht unbedingt NTP obwohl es natürlich trotzdem eine sehr elegante Lösung darstellt. 🙂

    Und alle Server (z.B. alle auf http://www.eecis.udel.edu/~mills/ntp/clock1a.html) geben die Zahl der seit dem 1.1.1900 um 0:00:00 Uhr verstrichenen Sekunden zurück, wenn man sie auf Port 37 anspricht, ja?

    Epochsekunden? Eigentlich glaube ich dass das ganze ein bisschen komplizierter abläuft aber ich habe die entsprechenden RFCs auch noch nicht gelesen. *g*



  • Since NTP timestamps are cherished data and, in fact, represent the main
    product of the protocol, a special timestamp format has been
    established. NTP timestamps are represented as a 64-bit unsigned fixed-
    point number, in seconds relative to 0h on 1 January 1900. The integer
    part is in the first 32 bits and the fraction part in the last 32 bits.
    This format allows convenient multiple-precision arithmetic and
    conversion to Time Protocol representation (seconds), but does
    complicate the conversion to ICMP Timestamp message representation
    (milliseconds). The precision of this representation is about 200
    picoseconds, which should be adequate for even the most exotic
    requirements.

    ftp://ftp.rfc-editor.org/in-notes/rfc1305.txt

    🙂



  • Simpel aber nicht ganz so einfach zu automatisieren gibts auch noch das hier:

    ftp://ftp.rfc-editor.org/in-notes/rfc867.txt



  • Sorry, habe mich geirrt, sind tatsächlich Sekunden seit 1900 und nicht Unix-Epoch + nochwas, wenn RFCs nur nicht manchmal so mühsam zu lesen wären...

    edit: Hm, zu spät. Geistige Notiz an mich: Nicht mehr so lange Tabs offen lassen und mit dem Beantworten warten... 🙂





  • Luckie schrieb:

    http://www.luckie-online.de/ -> InetTime. 😉

    Wenn du auch noch sagen könntest, wie DU das bewerkstelligt hast, wäre das echt super.

    P.S.: Komisch, ich will immer Programme schreiben, die du schon längst geschrieben hast. (siehe z.B. NetSend) 😉



  • Ich kann dich beruhigen WebFritzi - es ist nicht leicht, was zufinden, was es nicht gibt. Ich glaub sogar Dönerbudensimulationen, Mückenpopulationsberechnung und eine Berechnung wieviel Toilettenpapier man in der Woche braucht ( in cm^2 ) gibts schon. Auch wenn ich selbst noch keine gesehen habe 😉



  • WebFritzi schrieb:

    Luckie schrieb:

    http://www.luckie-online.de/ -> InetTime. 😉

    Wenn du auch noch sagen könntest, wie DU das bewerkstelligt hast, wäre das echt super.

    Source ist doch dabei. Ist zwar Delphi-Language aber die API-Funktionen heißen genauso. Kommentiert ist der Source, glaube ich, auch noch.

    P.S.: Komisch, ich will immer Programme schreiben, die du schon längst geschrieben hast. (siehe z.B. NetSend) 😉

    Einer ist immer schneller. :p



  • #ifndef TimeSyncH
    #define TimeSyncH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <NMDayTim.hpp>
    #include <Psock.hpp>
    #include <ExtCtrls.hpp>
    #include <Graphics.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
            TNMDayTime *time;
            TButton *Button1;
            TButton *Button2;
            TEdit *Edit1;
            TImage *Image1;
            void __fastcall Button1Click(TObject *Sender);
            void __fastcall Button2Click(TObject *Sender);
            void __fastcall VerbFehler(TObject *Sender);
            void __fastcall WrongHost(bool &Handled);
    private:	// Anwender-Deklarationen
    public:		// Anwender-Deklarationen
            __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include <dos.h>
    #pragma hdrstop
    
    #include "TimeSync.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    AnsiString output="Uhrzeit: ";
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    /*Edit1->Text=time->DayTimeStr ;
      AnsiString tmp=Edit1->Text;
      int i=1;
      while(tmp[i++]!=' ');
      while(tmp[i++]!=' ');
      while(tmp[i++]!=' ');
      test->Text=Edit1->Text.SubString(i,8);
      struct  time t;
      t.ti_hour=StrToInt(test->Text.SubString(1,2));
      t.ti_min=StrToInt(test->Text.SubString(4,2));
      t.ti_sec=StrToInt(test->Text.SubString(7,2));
      settime(&t);*/
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      AnsiString tmp=time->DayTimeStr;
      int i=1;
      while(tmp[i++]!=' ');
      while(tmp[i++]!=' ');
      while(tmp[i++]!=' ');
      Edit1->Text=output+tmp.SubString(i,8);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      AnsiString tmp=time->DayTimeStr;
      int i=1;
      while(tmp[i++]!=' ');
      while(tmp[i++]!=' ');
      while(tmp[i++]!=' ');
      Edit1->Text=output+tmp.SubString(i,8);
      tmp=tmp.SubString(i,8);
      struct time t;
      t.ti_hour=StrToInt(tmp.SubString(1,2));
      t.ti_min=StrToInt(tmp.SubString(4,2));
      t.ti_sec=StrToInt(tmp.SubString(7,2));
      settime(&t);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::VerbFehler(TObject *Sender)
    {
      Edit1->Text="Verbindungsfehler";        
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::WrongHost(bool &Handled)
    {
      Edit1->Text="Host Fehler";        
    }
    //---------------------------------------------------------------------------
    


  • Bei mir (BCB3) gibt es kein TNMDayTime-Objekt. Ich würde das auch gerne auf LowLevel-Ebene über Sockets machen.

    @unreg: Wo werden denn bitte die Funktionen "VerFehler" und "WrongHost" aufgerufen?



  • Meins ist low level. 😉



  • Luckie schrieb:

    Meins ist low level. 😉

    Und genau deswegen werd ich mir das auch mal anschauen. Sorry, ich wusst nicht, dass da auch der Code dabei ist.



  • Mehr Low-Level geht's nicht (außer asm):

    /*------------------------------------------------------------------------
       NETTIME.C - Zeit von Internet-Server erfragen und als Systemzeit setzen
                    (c) Charles Petzold, 1998
      -------------------------------------------------------------------------*/
    
    #include <windows.h>
    #include "resource.h"
    
    #define WM_SOCKET_NOTIFY (WM_USER + 1)
    #define ID_TIMER         1
    
    LRESULT CALLBACK WndProc   (HWND, UINT, WPARAM, LPARAM) ;
    BOOL    CALLBACK MainDlg   (HWND, UINT, WPARAM, LPARAM) ;
    BOOL    CALLBACK ServerDlg (HWND, UINT, WPARAM, LPARAM) ;
    
    void ChangeSystemTime (HWND hwndEdit, ULONG ulTime) ;
    void FormatUpdatedTime (HWND hwndEdit, SYSTEMTIME * pstOld, SYSTEMTIME * pstNew) ;
    void EditPrintf (HWND hwndEdit, TCHAR * szFormat, ...) ;
    HINSTANCE hInst ;
    HWND      hwndModeless ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
         static TCHAR szAppName[] = TEXT ("NetTime") ;
         HWND         hwnd ;
         MSG          msg ;
         RECT         rect ;
         WNDCLASS     wndclass ;
    
         hInst = hInstance ;
    
         wndclass.style         = 0 ;
         wndclass.lpfnWndProc   = WndProc ;
         wndclass.cbClsExtra    = 0 ;
         wndclass.cbWndExtra    = 0 ;
         wndclass.hInstance     = hInstance ;
         wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
         wndclass.hCursor       = NULL ;
         wndclass.hbrBackground = NULL ;
         wndclass.lpszMenuName  = NULL ;
         wndclass.lpszClassName = szAppName ;
    
         if (!RegisterClass (&wndclass))
         {
              // UNICODE-Kompilierung ist die einzige realistische Fehlermöglichkeit
              MessageBox (NULL, TEXT ("Programm arbeitet mit Unicode und setzt Windows NT voraus!"),
                          szAppName, MB_ICONERROR) ;
              return 0 ;
         }
              // Programmfenster anlegen
         hwnd = CreateWindow (szAppName, TEXT ("Systemzeit aus Internet beziehen"),
                              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL) ;
    
         // modusloses Dialogfeld anlegen
         hwndModeless = CreateDialog (hInstance, szAppName, hwnd, MainDlg) ;
    
         // Abmessungen des Hauptfensters denen des Dialogfelds anpassen
         // und beide Fenster anzeigen
         GetWindowRect (hwndModeless, &rect) ;
          AdjustWindowRect (&rect, WS_CAPTION | WS_BORDER, FALSE) ;
    
         SetWindowPos (hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE) ;
    
         ShowWindow (hwndModeless, SW_SHOW) ;
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ;
    
         // Nachrichtenschleife mit Erweiterung für das moduslose Dialogfeld
         while (GetMessage (&msg, NULL, 0, 0))
         {
              if (hwndModeless == 0 || !IsDialogMessage (hwndModeless, &msg))
              {
                   TranslateMessage (&msg) ;
                   DispatchMessage (&msg) ;
              }
         }
         return msg.wParam ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         switch (message)
         {
         case WM_SETFOCUS:
              SetFocus (hwndModeless) ;
              return 0 ;
    
         case WM_DESTROY:
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    BOOL CALLBACK MainDlg (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         static char   szIPAddr[32] = { "132.163.135.130" } ;
         static HWND   hwndButton, hwndEdit ;
         static SOCKET sock ;
         static struct sockaddr_in sa ;
         static TCHAR  szOKLabel[32] ;
         int           iError, iSize ;
         unsigned long ulTime ;
         WORD          wEvent, wError ;
         WSADATA       WSAData ;
    
         switch (message)
         {
         case WM_INITDIALOG:
              hwndButton = GetDlgItem (hwnd, IDOK) ;
              hwndEdit = GetDlgItem (hwnd, IDC_TEXTOUT) ;
              return TRUE ;
    
         case WM_COMMAND:
              switch (LOWORD (wParam))
              {
              case IDC_SERVER:  // Auswahl eines anderen Zeit-Servers
                   DialogBoxParam (hInst, TEXT ("Servers"), hwnd, ServerDlg, (LPARAM) szIPAddr) ;
                   return TRUE ;
    
              case IDOK:
                   // WSAStartup aufrufen und Beschreibungstext anzeigen
                   if (iError = WSAStartup (MAKEWORD(2,0), &WSAData))
                   {
                        EditPrintf (hwndEdit, TEXT ("WSAStartup-Fehler #%i.\r\n"), iError) ;
                        return TRUE ;
                   }
                   EditPrintf (hwndEdit, TEXT ("%hs gestartet.\r\n"), WSAData.szDescription);
    
                   // Socket öffnen
                   sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
    
                   if (sock == INVALID_SOCKET)
                   {
                        EditPrintf (hwndEdit,
                                    TEXT ("Fehler beim Anlegen des Sockets: #%i.\r\n"),
                                    WSAGetLastError ()) ;
                        WSACleanup () ;
                        return TRUE ;
                   }
                   EditPrintf (hwndEdit, TEXT ("Socket %i angelegt.\r\n"), sock) ;
    
                   // WSAAsyncSelect aufrufen
                   if (SOCKET_ERROR == WSAAsyncSelect (sock, hwnd, WM_SOCKET_NOTIFY,
                                                        FD_CONNECT | FD_READ))
                   {
                        EditPrintf (hwndEdit,
                                    TEXT ("WSAAsyncSelect-Fehler #%i.\r\n"),
                                    WSAGetLastError ()) ;
                        closesocket (sock) ;
                        WSACleanup () ;
                        return TRUE ;
                   }
    
                   // Aufruf von "connect" mit IP-Adresse und Portnummer des Zeitservers
                   sa.sin_family           = AF_INET ;
                   sa.sin_port             = htons (IPPORT_TIMESERVER) ;
                   sa.sin_addr.S_un.S_addr = inet_addr (szIPAddr) ;
    
                   connect(sock, (SOCKADDR *) &sa, sizeof (sa)) ;
    
                   // "connect" wird wegen den vorherigen WSAAsyncSelect-Aufrufs SOCKET_ERROR liefern,
                   // da die Funktion als potentiell blockierende Funktion die Kontrolle unmittelbar
                   // (also noch vor dem Herstellen der Verbindung) zurückgibt. Der Statuscode
                   // WSAEWOULDBLOCK ist deshalb nicht als Fehler zu betrachten.
                   // Hier die Reaktion auf unwartete Fehler:
                   if (WSAEWOULDBLOCK != (iError = WSAGetLastError ()))
                   {
                        EditPrintf (hwndEdit, TEXT ("Connect-Fehler #%i.\r\n"), iError) ;
                        closesocket (sock) ;
                        WSACleanup () ;
                        return TRUE ;
                   }
                   EditPrintf (hwndEdit, TEXT ("Verbinde mit %hs..."), szIPAddr) ;
    
                   // Das Ergebnis des "connect"-Aufrufs wird über WM_SOCKET_NOTIFY angeliefert.
                   // Timer setzen und Schaltflächenbeschriftung auf "Abbrechen" ändern
                   SetTimer (hwnd, ID_TIMER, 1000, NULL) ;
                   GetWindowText (hwndButton, szOKLabel, sizeof (szOKLabel) / sizeof (TCHAR)) ;
                   SetWindowText (hwndButton, TEXT ("Abbruch")) ;
                   SetWindowLong (hwndButton, GWL_ID, IDCANCEL) ;
                   return TRUE ;
    
              case IDCANCEL:
                   closesocket (sock) ;
                   sock = 0 ;
                   WSACleanup () ;
                   SetWindowText (hwndButton, szOKLabel) ;
                   SetWindowLong (hwndButton, GWL_ID, IDOK) ;
    
                   KillTimer (hwnd, ID_TIMER) ;
                   EditPrintf (hwndEdit, TEXT ("\r\nSocket geschlossen.\r\n")) ;
                   return TRUE ;
    
              case IDC_CLOSE:
                   if (sock)
                        SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
    
                   DestroyWindow (GetParent (hwnd)) ;
                   return TRUE ;
              }
              return FALSE ;
    
         case WM_TIMER:
              EditPrintf (hwndEdit, TEXT (".")) ;
              return TRUE ;
    
         case WM_SOCKET_NOTIFY:
              wEvent = WSAGETSELECTEVENT (lParam) ;   // d.h. LOWORD
              wError = WSAGETSELECTERROR (lParam) ;   // d.h. HIWORD
    
              // Behandlung zweier für WSAAsyncSelect spezifizierte Ereignisse
              switch (wEvent)
              {
              case FD_CONNECT:                   // Rückmeldung von connect()
                   EditPrintf (hwndEdit, TEXT ("\r\n")) ;
    
                   if (wError)
                   {
                        EditPrintf (hwndEdit, TEXT ("Connect Fehler #%i."), wError) ;
                        SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
                        return TRUE ;
                   }
                   EditPrintf (hwndEdit, TEXT ("Verbunden mit %hs.\r\n"), szIPAddr) ;
    
                   // Versuche Daten zu empfangen. Der Aufruf wird einen WSAEWOULDBLOCK-Fehler
                   // und ein FD_READ-Ereignis generieren.
                   recv (sock, (char *) &ulTime, 4, MSG_PEEK) ;
                   EditPrintf (hwndEdit, TEXT ("Warte auf Empfang...")) ;
                    return TRUE ;
    
               case FD_READ:                     // Rückmeldung von recv()
                   KillTimer (hwnd, ID_TIMER) ;
                   EditPrintf (hwndEdit, TEXT ("\r\n")) ;
    
                   if (wError)
                   {
                        EditPrintf (hwndEdit, TEXT ("FD_READ error #%i."), wError) ;
                        SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
                        return TRUE ;
                   }
                   // Zeit abfragen und Bytes vertauschen
                   iSize = recv (sock, (char *) &ulTime, 4, 0) ;
                   ulTime = ntohl (ulTime) ;
                   EditPrintf (hwndEdit,
                               TEXT ("Aktuelle Zeit ist: %u Sekunden ")
                               TEXT ("seit 1.1.1900, 0:00 Uhr.\r\n"), ulTime) ;
    
                   // Systemzeit setzen
                   ChangeSystemTime (hwndEdit, ulTime) ;
                   SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ;
                   return TRUE ;
              }
              return FALSE ;
         }
         return FALSE ;
    }
    
    BOOL CALLBACK ServerDlg (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         static char * szServer ;
         static WORD   wServer = IDC_SERVER1 ;
         char          szLabel [64] ;
    
         switch (message)
         {
         case WM_INITDIALOG:
              szServer = (char *) lParam ;
              CheckRadioButton (hwnd, IDC_SERVER1, IDC_SERVER10, wServer) ;
              return TRUE ;
    
         case WM_COMMAND:
              switch (LOWORD (wParam))
              {
              case IDC_SERVER1:
              case IDC_SERVER2:
              case IDC_SERVER3:
              case IDC_SERVER4:
              case IDC_SERVER5:
              case IDC_SERVER6:
              case IDC_SERVER7:
              case IDC_SERVER8:
              case IDC_SERVER9:
              case IDC_SERVER10:
                   wServer = LOWORD (wParam) ;
                   return TRUE ;
    
              case IDOK:
                   GetDlgItemTextA (hwnd, wServer, szLabel, sizeof (szLabel)) ;
                   strtok (szLabel, "(") ;
                   strcpy (szServer, strtok (NULL, ")")) ;
                   EndDialog (hwnd, TRUE) ;
                   return TRUE ;
    
              case IDCANCEL:
                   EndDialog (hwnd, FALSE) ;
                   return TRUE ;
              }
              break ;
         }
         return FALSE ;
    }
    
    void ChangeSystemTime (HWND hwndEdit, ULONG ulTime)
    {
         FILETIME      ftNew ;
         LARGE_INTEGER li ;
         SYSTEMTIME    stOld, stNew ;
    
         GetLocalTime (&stOld) ;
    
         stNew.wYear         = 1900 ;
         stNew.wMonth        = 1 ;
         stNew.wDay          = 1 ;
         stNew.wHour         = 0 ;
         stNew.wMinute       = 0 ;
         stNew.wSecond       = 0 ;
         stNew.wMilliseconds = 0 ;
    
         SystemTimeToFileTime (&stNew, &ftNew) ;
         li = * (LARGE_INTEGER *) &ftNew ;
         li.QuadPart += (LONGLONG) 10000000 * ulTime ;
         ftNew = * (FILETIME *) &li ;
         FileTimeToSystemTime (&ftNew, &stNew) ;
    
         if (SetSystemTime (&stNew))
         {
              GetLocalTime (&stNew) ;
              FormatUpdatedTime (hwndEdit, &stOld, &stNew) ;
         }
         else
              EditPrintf (hwndEdit, TEXT ("Konnte Systemzeit nicht ändern.")) ;
    }
    
    void FormatUpdatedTime (HWND hwndEdit, SYSTEMTIME * pstOld, SYSTEMTIME * pstNew)
    {
         TCHAR szDateOld [64], szTimeOld [64], szDateNew [64], szTimeNew [64] ;
    
         GetDateFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | DATE_SHORTDATE,
                        pstOld, NULL, szDateOld, sizeof (szDateOld)) ;
    
         GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE |
                             TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
                        pstOld, NULL, szTimeOld, sizeof (szTimeOld)) ;
    
         GetDateFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE | DATE_SHORTDATE,
                        pstNew, NULL, szDateNew, sizeof (szDateNew)) ;
    
         GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE |
                             TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
                        pstNew, NULL, szTimeNew, sizeof (szTimeNew)) ;
    
         EditPrintf (hwndEdit,
                     TEXT ("Systemdatum und Systemzeit wurden von")
                     TEXT ("\r\n\t%s, %s.%03i auf\r\n\t%s, %s.%03i korrigiert."),
                     szDateOld, szTimeOld, pstOld->wMilliseconds,
                     szDateNew, szTimeNew, pstNew->wMilliseconds) ;
    }
    
    void EditPrintf (HWND hwndEdit, TCHAR * szFormat, ...)
    {
         TCHAR   szBuffer [1024] ;
         va_list pArgList ;
    
         va_start (pArgList, szFormat) ;
         wvsprintf (szBuffer, szFormat, pArgList) ;
         va_end (pArgList) ;
         SendMessage (hwndEdit, EM_SETSEL, (WPARAM) -1, (LPARAM) -1) ;
         SendMessage (hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) szBuffer) ;
         SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;
    }
    

Anmelden zum Antworten