Set time programmatically using C#

前端 未结 5 2260
礼貌的吻别
礼貌的吻别 2020-12-06 18:41

What is the best way to set the time on a remote machine remotely? The machine is running Windows XP and is receiving the new time through a web service call. The goal is

5条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-06 19:23

    The way to query a network machine for it's system time is NetRemoteTOD.

    Here's code to do it in Delphi (a usage example is posted below).

    Since it relies on Windows API calls, it shouldn't be too different in C#.

    unit TimeHandler;
    
    interface
    
    type
      TTimeHandler = class
      private
        FServerName : widestring;
      public
        constructor Create(servername : widestring);
        function RemoteSystemTime : TDateTime;
        procedure SetLocalSystemTime(settotime : TDateTime);
      end;
    
    implementation
    
    uses
      Windows, SysUtils, Messages;
    
    function NetRemoteTOD(ServerName :PWideChar; var buffer :pointer) : integer; stdcall; external 'netapi32.dll';
    function NetApiBufferFree(buffer : Pointer) : integer; stdcall; external 'netapi32.dll';
    
    type
      //See MSDN documentation on the TIME_OF_DAY_INFO structure.
      PTime_Of_Day_Info = ^TTime_Of_Day_Info;
      TTime_Of_Day_Info = record
        ElapsedDate : integer;
        Milliseconds : integer;
        Hours : integer;
        Minutes : integer;
        Seconds : integer;
        HundredthsOfSeconds : integer;
        TimeZone : LongInt;
        TimeInterval : integer;
        Day : integer;
        Month : integer;
        Year : integer;
        DayOfWeek : integer;
      end;
    
    constructor TTimeHandler.Create(servername: widestring);
    begin
      inherited Create;
      FServerName := servername;
    end;
    
    function TTimeHandler.RemoteSystemTime: TDateTime;
    var
      Buffer : pointer;
      Rek : PTime_Of_Day_Info;
      DateOnly, TimeOnly : TDateTime;
      timezone : integer;
    begin
      //if the call is successful...
      if 0 = NetRemoteTOD(PWideChar(FServerName),Buffer) then begin
        //store the time of day info in our special buffer structure
        Rek := PTime_Of_Day_Info(Buffer);
    
        //windows time is in GMT, so we adjust for our current time zone
        if Rek.TimeZone <> -1 then
          timezone := Rek.TimeZone div 60
        else
          timezone := 0;
    
        //decode the date from integers into TDateTimes
        //assume zero milliseconds
        try
          DateOnly := EncodeDate(Rek.Year,Rek.Month,Rek.Day);
          TimeOnly := EncodeTime(Rek.Hours,Rek.Minutes,Rek.Seconds,0);
        except on e : exception do
          raise Exception.Create(
                                 'Date retrieved from server, but it was invalid!' +
                                 #13#10 +
                                 e.Message
                                );
        end;
    
        //translate the time into a TDateTime
        //apply any time zone adjustment and return the result
        Result := DateOnly + TimeOnly - (timezone / 24);
      end  //if call was successful
      else begin
        raise Exception.Create('Time retrieval failed from "'+FServerName+'"');
      end;
    
      //free the data structure we created
      NetApiBufferFree(Buffer);
    end;
    
    procedure TTimeHandler.SetLocalSystemTime(settotime: TDateTime);
    var
      SystemTime : TSystemTime;
    begin
      DateTimeToSystemTime(settotime,SystemTime);
      SetLocalTime(SystemTime);
      //tell windows that the time changed
      PostMessage(HWND_BROADCAST,WM_TIMECHANGE,0,0);
    end;
    

    And here is the usage example:

    procedure TfrmMain.SynchLocalTimeWithServer;
    var
      tod : TTimeHandler;
    begin
      tod := TTimeHandler.Create(cboServerName.Text);
      try
        tod.SetLocalSystemTime(tod.RemoteSystemTime);
      finally
        FreeAndNil(tod);
      end;  //try-finally
    end;
    

提交回复
热议问题