Contents
有些时候我们不希望用户在使用我们的软件时修改系统时间,那么怎么检测用户是否修改系统时间呢?Windows会在系统时间修改时发送WM_TIMECHANGE消息,所以可以在C++的WindowProc函数中处理这个消息。如果是C#,可以直接用SystemEvents.TimeChanged事件。这个事件有个bug,就是每次都会被触发两次。
如果还想做的更智能一点,想把时间再改回去,就需要知道用户修改时间前的时间是什么。一个可行的办法是在程序开始运行时记一个开始时间,然后用Stopwatch这个类来掐表算算过去了多长时间。给Windows设置时间需要用到SetSystemTime这个API。
下面是示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| public class Program { private static Stopwatch s_Stopwatch; private static DateTime s_Start; private static int s_Count = 0;
[DllImport("kernel32.dll")] private extern static uint SetSystemTime(ref SYSTEMTIME lpSystemTime);
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; }
static void Main(string[] args) { SystemEvents.TimeChanged += (sender, eventArgs) => { if (s_Count == 1) { s_Count = 0; return; } var realTime = s_Start + s_Stopwatch.Elapsed; var newTime = DateTime.Now;
Console.WriteLine(newTime); Console.WriteLine("Should be:"); Console.WriteLine(realTime);
var utcTime = realTime.ToUniversalTime();
SYSTEMTIME systemtime = new SYSTEMTIME();
systemtime.wYear = (ushort)utcTime.Year; systemtime.wMonth = (ushort)utcTime.Month; systemtime.wDay = (ushort)utcTime.Day; systemtime.wHour = (ushort)utcTime.Hour; systemtime.wMinute = (ushort)utcTime.Minute; systemtime.wSecond = (ushort)utcTime.Second; systemtime.wMilliseconds = (ushort)utcTime.Millisecond;
SetSystemTime(ref systemtime); Console.WriteLine("Change back!"); Console.WriteLine();
s_Count++; };
s_Stopwatch = new Stopwatch(); s_Start = DateTime.Now; s_Stopwatch.Start(); Console.ReadLine(); s_Stopwatch.Stop(); } }
|
下面是一个运行结果,可以看到时间改了两次,因为我们的程序改了一次。注意上面代码中的s_Count
用来绕过上面提到的触发两次event的bug,如果没有这个话,这段代码会死循环下去。。。因为我们一直再改时间。当然也可以做一个时间的比较,小于某个值我们就认为一样,就不修改了。
1 2 3 4 5 6 7 8 9
| 9/15/2015 8:01:32 PM Should be: 9/16/2015 8:01:32 PM Change back!
9/16/2015 8:01:32 PM Should be: 9/16/2015 8:01:32 PM Change back!
|
两外一个要注意的是如果程序是Windows服务的话,需要起一个隐藏的窗口来处理消息,不然TimeChanged
收不到。
如果想直接禁止用户修改时间,可以参见这篇文章How to Allow or Prevent Specific Users and Groups from Changing the Date and Time in Windows。里面提供了两个方法:
- 修改Local Security Policy中的Change the system time。
- 通过
ntrights运行ntrights -U "Administrators" -R SeSystemtimePrivilege
来禁止修改时间,运行ntrights -U "Administrators" -R SeSystemtimePrivilege
来允许修改时间。