I'm trying to set Windows SystemTime in a c# Application on Windows. I've implemented the example that is in every forum (including here) but it's not responding. I have a private class with two methods: GetSystemTime() and SetSystemTime(). GetSystemTime is working fine, but SetSystemTime is not setting the time I'm trying to pass from GetNetworkTime(). I'm doing something wrong? I've researched and I don't know if it's a privilege problem (I'm logged as Administrator, it shouldn't) or maybe a problem with date format.
The thing is: Should I see change in System clock when SetSystemTime() finishes? How I know it's running well? Because I'm not seeing any changes. Here I copy the class, and also GetNetworkTime Method, which get the actual hour from and NTP Server.
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));
}
The MSDN says
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724942%28v=vs.85%29.aspx for whole page.
Did you try to check the return value and hence, last error ?
Here is a code sample to get return value and last error code : (just replace your own "SetSystemTime" call)
var ret = SetSystemTime(ref systime);
Console.WriteLine("SetSystemTime return : " + ret);
System.Console.WriteLine("Last error : " + GetLastError());
Don't forget to add import for GetLastError :
[DllImport("kernel32.dll")]
static extern uint GetLastError();
edit : I've just made a try, I get error "ERROR_INVALID_PARAMETER 87 (0x57) The parameter is incorrect.".
So, following this advice, I've read again your code :
You wrote :
systime.wHour = (ushort)d.Year;
instead of :
systime.wYear = (ushort)d.Year;
Fixed it, and then, no more error.
In order to change the system time you need to have a following privilege: SeSystemTimePrivilege
Or you can run your application as administrator. The fact that you are logged as administrator won't change that because it's linked to the UAC. You can disable the UAC completely but I wouldn't recommend that.
User contributions licensed under CC BY-SA 3.0