2014-10-08 72 views
1

我想在Windows上的c#应用程序中设置Windows SystemTime。我已经实现了每个论坛(包括这里)的例子,但它没有回应。 我有一个私人类有两种方法: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; 

固定,然后,没有更多的错误。

+0

感谢您的回答!我修复了它。但是当我调用Datetime.Now时,它不会更新,而且我仍然看到原始值。你知道为什么吗? – user1545878 2014-10-08 14:28:26

+1

除了你的回答,我有一个权限问题。我以管理员身份打开VS,它工作正常! – user1545878 2014-10-08 15:23:25

+0

你看过GetLastError来找出它吗?我想它也应该为这类错误提供有用的信息;) – AFract 2014-10-08 17:17:42

1

为了改变,你需要有以下权限的系统时间:SeSystemTimePrivilege

或者你可以运行你的应用程序作为管理员。以管理员身份登录的事实不会因为它与UAC相关而更改。您可以完全禁用UAC,但我不会推荐。