установить системное время C # не работает

1

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

Дело в том: должен ли я видеть изменение в системных часах, когда заканчивается 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));
    }
Теги:
set
datetime
time

2 ответа

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();                

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

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

Вы написали:

   systime.wHour = (ushort)d.Year;

вместо:

   systime.wYear = (ushort)d.Year;

Исправлено, а затем больше нет ошибок.

  • 0
    Спасибо за Ваш ответ! Я исправил это. Но когда я вызываю Datetime.Now, он не обновляется, и я все еще вижу исходное значение. Ты знаешь почему?
  • 1
    Помимо вашего ответа у меня была проблема с привилегиями. Я открыл VS как администратор, и это сработало!
Показать ещё 1 комментарий
1

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню