2014-10-08 2 views
1

Я пытаюсь установить Windows SystemTime в приложение C# в Windows. Я реализовал пример, который есть на каждом форуме (включая здесь), но он не отвечает. У меня есть частный класс с двумя методами: GetSystemTime() и SetSystemTime(). GetSystemTime работает нормально, но SetSystemTime не устанавливает время, которое я пытаюсь передать из GetNetworkTime(). Я что-то не так? Я исследовал, и я не знаю, является ли это проблемой с привилегиями (я зарегистрирован как администратор, это не должно) или, может быть, проблема с форматом даты.установить системное время C# не работает

Дело в следующем: должен ли я видеть изменение в системных часах, когда SetSystemTime() заканчивается? Как я знаю, что он работает хорошо? Потому что я не вижу никаких изменений. Здесь я копирую класс, а также метод GetNetworkTime, который получает фактический час и NTP-сервер.

public static class SystemTime 
    { 
     [DllImport("kernel32.dll", SetLastError = true)] 
     private extern static void GetSystemTime(ref SYSTEMTIME systime); 
     [DllImport("kernel32.dll", SetLastError = true)] 
     private extern static uint SetSystemTime(ref SYSTEMTIME systime); 

     private struct SYSTEMTIME 
     { 
      public ushort wYear; 
      public ushort wMonth; 
      public ushort wDayOfWeek; 
      public ushort wDay; 
      public ushort wHour; 
      public ushort wMinute; 
      public ushort wSecond; 
      public ushort wMilliseconds; 
     } 

     private static void GetTime() 
     { 
      // Call the native GetSystemTime method 
      // with the defined structure. 
      SYSTEMTIME stime = new SYSTEMTIME(); 
      GetSystemTime(ref stime); 
     } 

     public static void SetTime() 
     { 
      GetTime(); 
      SYSTEMTIME systime = new SYSTEMTIME(); 
      try 
      { 
       DateTime d = Intex.Core.Utils.Common.GetNetworkTime(); 

       systime.wHour = (ushort)d.Year; 
       systime.wMonth = (ushort)d.Month; 
       systime.wDayOfWeek = (ushort)d.DayOfWeek; 
       systime.wDay = (ushort)d.Day; 
       systime.wHour = (ushort)d.Hour; 
       systime.wMinute = (ushort)d.Minute; 
       systime.wSecond = (ushort)d.Second; 
       systime.wMilliseconds = (ushort)d.Millisecond; 

       SetSystemTime(ref systime); 
       GetTime(); 
      } 
      catch (Exception) 
      { 
       GetSystemTime(ref systime); 
       SetSystemTime(ref systime); 
      } 

     } 
    } 


public static DateTime GetNetworkTime() 
    { 
     //default Windows time server 
     string ntpServer = ConfigurationManager.AppSettings["NTPServer"]; 

     // NTP message size - 16 bytes of the digest (RFC 2030) 
     var ntpData = new byte[48]; 

     //Setting the Leap Indicator, Version Number and Mode values 
     ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode) 

     var addresses = Dns.GetHostEntry(ntpServer).AddressList; 

     //The UDP port number assigned to NTP is 123 
     var ipEndPoint = new IPEndPoint(addresses[0], 123); 
     //NTP uses UDP 
     var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 

     socket.Connect(ipEndPoint); 

     //Stops code hang if NTP is blocked 
     socket.ReceiveTimeout = 3000; 

     socket.Send(ntpData); 
     socket.Receive(ntpData); 
     socket.Close(); 

     //Offset to get to the "Transmit Timestamp" field (time at which the reply 
     //departed the server for the client, in 64-bit timestamp format." 
     const byte serverReplyTime = 40; 

     //Get the seconds part 
     ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime); 

     //Get the seconds fraction 
     ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4); 

     //Convert From big-endian to little-endian 
     intPart = SwapEndianness(intPart); 
     fractPart = SwapEndianness(fractPart); 

     var milliseconds = (intPart * 1000) + ((fractPart * 1000)/0x100000000L); 

     //**UTC** time 
     var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds); 

     return networkDateTime.ToLocalTime();    
    } 

    static uint SwapEndianness(ulong x) 
    { 
     return (uint)(((x & 0x000000ff) << 24) + 
         ((x & 0x0000ff00) << 8) + 
         ((x & 0x00ff0000) >> 8) + 
         ((x & 0xff000000) >> 24)); 
    } 

ответ

2

MSDN от говорит

Если функция завершается успешно, возвращаемое значение отлично от нуля. Если функция не работает, возвращаемое значение равно нулю. Чтобы получить расширенную информацию об ошибке, вызовите GetLastError.

См. http://msdn.microsoft.com/en-us/library/windows/desktop/ms724942%28v=vs.85%29.aspx для всей страницы.

Вы пытались проверить возвращаемое значение и, следовательно, последнюю ошибку?

Вот пример кода, чтобы получить возвращаемое значение и код последней ошибки: (просто заменить свой собственный «SetSystemTime» вызов)

var ret = SetSystemTime(ref systime); 
Console.WriteLine("SetSystemTime return : " + ret); 
System.Console.WriteLine("Last error : " + GetLastError()); 

Не забудьте добавить импорт для GetLastError:

[DllImport("kernel32.dll")] 
static extern uint GetLastError();     

Редактирование: Я только что попытался, я получаю ошибку "ERROR_INVALID_PARAMETER 87 (0x57) Параметр неверен.".

Итак, следуя этому совету, я прочитал еще раз код:

Вы писали:

systime.wHour = (ushort)d.Year; 

вместо:

systime.wYear = (ushort)d.Year; 

Fixed, а затем, не более ошибка.

+0

Спасибо за ваш ответ! Я исправил это. Но когда я вызываю Datetime.Now, он не обновляется, и я все еще вижу исходное значение. Ты знаешь почему? – user1545878

+1

Помимо вашего ответа, у меня была проблема с привилегиями. Я открыл VS как Администратор, и это сработало! – user1545878

+0

Вы посмотрели на GetLastError, чтобы понять это? Я полагаю, он также должен предоставить полезную информацию для такого рода ошибок;) – AFract

1

Для того, чтобы изменить системное время, необходимо иметь следующую привилегию: SeSystemTimePrivilege

Или вы можете запустить приложение от имени администратора. Тот факт, что вы зарегистрированы как администратор, не изменится, потому что он связан с UAC. Вы можете полностью отключить UAC, но я бы не рекомендовал этого.

Смежные вопросы