2014-10-08 100 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,但我不會推薦。