七、
在驱动中获取系统时间
在编程中,经常需要获得系统时间,或是需要获得一个从启动开始的毫秒数。前者往往是为了日志记录,后者很适合用来获得一个随机数种子。
7.1 获取启动毫秒数
在ring3我们可以通过一个GetTickCount函数来获得自系统启动开始的毫秒数,在ring0也有一个与之对应的KeQueryTickCount函数。
不幸的是,这个函数并不能直接返回毫秒数,它返回的是“滴答”数,而一个时钟“滴答”到底是多久,这在不同的系统中可能是不同的,因此我们还需要另外一个函数的辅助,即KeQueryTimeIncrement函数。
KeQueryTimeIncrement函数可以返回一个“滴答”表示多少个100纳秒,注意这里的单位是100纳秒。
Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛
22
7.2 获取系统时间
在ring3获取系统时间是非常简单的,我们直接使用GetLocalTime就可以通过一个系统时间结构体SYSTEMTIME来返回当前时间。
到了ring0我们可以使用KeQuerySystemTime来获得当前时间,但它其实是一个格林威治时间,与ring3得到的LocalTime不同,因此我们还需要使用ExSystemTimeToLocalTime函数将这个格林威治时间转换成当地时间。
事情到这里还没有结束,现在我们获得的当地时间不是一个容易阅读的格式,因此我们还要使用RltTimeToTimeFieldh函数将其转换成容易阅读的格式。
下面两个程序分别演示了获得启动毫秒数和当前时间的方法,它们被封装在两个函数里面,我们可以很方便地拿来使用。

VOID 

 MyGetTickCount() 

 { 

 LARGE_INTEGER tick_count; 

 ULONG inc; 

 inc=KeQueryTimeIncrement(); 

 KeQueryTickCount(&tick_count); 

 // 因为1毫秒等于1000000纳秒,而inc的单位是100纳秒 

 // 所以除以10000即得到当前毫秒数 

 tick_count.QuadPart*=inc; 

 tick_count.QuadPart/=10000; 

 KdPrint(("[Test]TickCount:%d",tick_count.QuadPart)); 

 } 

 VOID 

 MyGetCurrentTime() 

 { 

 LARGE_INTEGER CurrentTime; 

 LARGE_INTEGER LocalTime; 

 TIME_FIELDS TimeFiled; 

 staticWCHAR Time_String[32]={0}; 

 // 这里得到的其实是格林威治时间 

 KeQuerySystemTime(&CurrentTime); 

 // 转换成本地时间 

 ExSystemTimeToLocalTime(&CurrentTime,&LocalTime); 

 // 把时间转换为容易理解的形式 

 Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛 

 RtlTimeToTimeFields(&LocalTime,&TimeFiled); 

 KdPrint(("[Test]NowTime:%4d-%2d-%2d%2d:%2d:%2d", 

 TimeFiled.Year,TimeFiled.Month,TimeFiled.Day, 

 TimeFiled.Hour,TimeFiled.Minute,TimeFiled.Second)); 

 }


上面两段演示程序的测试效果如图7-1所示: