《天书夜读:从汇编语言到windows内核编程》九 时间与定时器
1)使用如下自定义函数获取自系统启动后经历的毫秒数:KeQueryTimeIncrement、KeQueryTickCount
void MyGetTickCount(PULONG msec)
{
LARGE_INTEGER tick_count;
ULONG myinc = KeQueryTimeIncrement();
//返回每次时钟中断,系统时间增加的纳秒数
KeQueryTickCount(&tick_count);
//返回自系统启动以来经历的定时器中断次数
tick_count.QuadPart *= myinc;
//计算从系统启动来经历多的总纳秒数(纳秒为一个单位)
tick_count.QuadPart /= ;
//转换为毫秒数(/10则取微秒)
*msec = tick_count.LowPart;
//取低字节(也可以取整个LAGER_INTEGER,改变传入参数)
}
测试代码:
DbgPrint("first: Hello,my salary!");
ULONG msec1 = 0L;
ULONG msec2 = 0L;
MyGetTickCount(&msec1);
KdPrint(("msec1:%d ms",msec1));
; i< ; i++)
{
MyGetTickCount(&msec2);
}
MyGetTickCount(&msec2);
KdPrint(("msec2:%d ms",msec2));
KdPrint((,(msec2-msec1)%));
输出结果:

2)获取当前系统时间:KeQuerySystemTime、ExSystemTimeToLocalTime、RtlTimeToTimeFields
PWCHAR MyCurTimeStr()
{
LARGE_INTEGER snow,now;
TIME_FIELDS now_fileds;
//定义静态变量缓冲区,这里先不考虑多线程隐患
] = {};
//获取标准时间(格林威治时间)
KeQuerySystemTime(&snow);
//转换为当地时间
ExSystemTimeToLocalTime(&snow,&now);
//转换为可理解要素
RtlTimeToTimeFields(&now,&now_fileds);
//格式化到字符串
RtlStringCchPrintfW(time_str,//缓冲区
*,//缓冲区长度
L"%04d-%02d-%02d %02d:%02d:%02d",
now_fileds.Year,now_fileds.Month,now_fileds.Day,
now_fileds.Hour,now_fileds.Minute,now_fileds.Second);
return time_str;
}
测试代码:KdPrint(("%ws",MyCurTimeStr()));
输出结果:

3)中断级:内核代码都运行在一定的中断级上,从微观上看代码的运行并不连续(异常发生、中断发生、线程切换等)。在高中断级运行的代码不会被在低中断级运行的代码打断,帮助文档对每个API应该在什么中断级范围内使用均有说明,中断级高低为:Dispatch>APC>Passive。
4)使用定时器:KeSetTimer、KeInitializeTimer、KeInitializeDpc、CustomDpc、KeCancelTimer
定时器的CustomDpc运行在APC中断级,所以定时器并不是可以用来定时做任何事情。
//内部时钟结构
typedef struct MY_TIMER_
{
KDPC dpc;//dpc
KTIMER timer;//定时器
LARGE_INTEGER due;//定时毫秒数
PKDEFERRED_ROUTINE func;//用户回调函数
PVOID privete_context;//用户上下文
}MY_TIMER,*PMY_TIMER;
BOOLEAN MyTimerInit(PMY_TIMER timer,PKDEFERRED_ROUTINE func);
BOOLEAN MyTimerSet(PMY_TIMER timer,ULONG msec,PVOID context);
BOOLEAN MyTimerDestroy(PMY_TIMER timer);
KDEFERRED_ROUTINE MyOnTimer;
//初始化内部时钟结构:PMY_TIMER,用户回调函数func
BOOLEAN MyTimerInit(PMY_TIMER pTimer,PKDEFERRED_ROUTINE func)
{
if( !pTimer ) return FALSE;
//初始化dpc:使用timer->dpc,回调函数TimerProc(内核回调函数)
//上下文设置为timer(用于传给用户回调函数)
KeInitializeDpc(&pTimer->dpc,(PKDEFERRED_ROUTINE)TimerProc,pTimer);
pTimer->func = func;//设置用户自定义回调函数
//初始化定时器
KeInitializeTimer(&pTimer->timer);
return TRUE;
}
//让内部时钟结构体的回调函数在n毫秒后执行:PMY_TIMER,定时毫秒数msec,用户上下文context
BOOLEAN MyTimerSet(PMY_TIMER timer,ULONG msec,PVOID context)
{
//定时时间值转换
//为正时指定相对系统的间隔时间:受系统时间设置影响
//为负则指定绝对系统时间:为纳秒数,不受系统时间设置影响
timer->due.QuadPart = -*(LONG)msec;//必须转为有符号类型
//用户私有上下文
timer->privete_context = context;
//添加定时器到系统定时器队列
return KeSetTimer(&timer->timer,timer->due,&timer->dpc);
}
//停止执行
BOOLEAN MyTimerDestroy(PMY_TIMER pTimer)
{
if(pTimer) return KeCancelTimer(&pTimer->timer);
else return FALSE;
}
//定时器回调函数:内核使用
void TimerProc(struct _KDPC *Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)
{
//这里传入的上下文是timer结构,用来下次再启动延时调用
PMY_TIMER pTimer = (PMY_TIMER)DeferredContext;
if(pTimer->func)//用户回调函数
{
PKDEFERRED_ROUTINE pFunc = (PKDEFERRED_ROUTINE)pTimer->func;//取得用户定义回调函数指针
pFunc(Dpc,(PVOID)pTimer->privete_context,SystemArgument1,SystemArgument2);//调用用户定义的回调函数
}
else KdPrint(("No callback function !\n"));
KeSetTimer(&pTimer->timer,pTimer->due,&pTimer->dpc);//再次设置定时器
}
测试代码:
#define SIZE 30
//用户上下文(自定义结构体)
typedef struct
{
WCHAR message[SIZE];
ULONG times;
}USER_CONTENT,*PUSER_CONTENT;
//用户回调函数
KDEFERRED_ROUTINE TimerProc;
//定时器回调函数:用户实现(函数名可更改)
void MyOnTimer(struct _KDPC *Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)
{
//在这里做OnTimer中要做的事,封装的好处就是编码时只关注自己想关注的东西
PUSER_CONTENT pMyContext = (PUSER_CONTENT)DeferredContext;
pMyContext->times++;
KdPrint(("第%d次调用定时器:%ws",pMyContext->times,pMyContext->message));
}
过程:
MY_TIMER timer;
USER_CONTENT MyContent;
ULONG i = ;
//用户自定义结构
RtlStringCbPrintfW((NTSTRSAFE_PWSTR)&MyContent.message,SIZE*sizeof(WCHAR),L"Hello Timer!");//格式串
MyContent.times = ;//计数值
//初始化定时器
MyTimerInit(&timer,(PKDEFERRED_ROUTINE)MyOnTimer);
//启动定时器
MyTimerSet(&timer,,(PVOID)&MyContent);
//等待一段时间
*10E8 );
//关闭定时器
MyTimerDestroy(&timer);
KdPrint(("定时器已经停止!"));
效果图:

《天书夜读:从汇编语言到windows内核编程》九 时间与定时器的更多相关文章
- 《天书夜读:从汇编语言到windows内核编程》五 WDM驱动开发环境搭建
(原书)所有内核空间共享,DriverEntery是内核程序入口,在内核程序被加载时,这个函数被调用,加载入的进程为system进程,xp下它的pid是4.内核程序的编写有一定的规则: 不能调用win ...
- 《天书夜读:从汇编语言到windows内核编程》八 文件操作与注册表操作
1)Windows运用程序的文件与注册表操作进入R0层之后,都有对应的内核函数实现.在windows内核中,无论打开的是文件.注册表或者设备,都需要使用InitializeObjectAttribut ...
- 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求
1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置. 2)DRIVER_OBJECT下的派遣函数(分发函 ...
- 《天书夜读:从汇编语言到windows内核编程》十一 用C++编写内核程序
---恢复内容开始--- 1) C++的"高级"特性,是它的优点也是它的缺点,微软对于使用C++写内核程序即不推崇也不排斥,使用C++写驱动需注意: a)New等操作符不能直接使用 ...
- 《天书夜读:从汇编语言到windows内核编程》四 windows内核调试环境搭建
1) 基础篇是讲理论的,先跳过去,看不到代码运行的效果要去记代码是一个痛苦的事情.这里先跳入探索篇.其实今天的确也很痛苦,这作者对驱动开发的编译与调试环境介绍得太模糊了,我是各种尝试,对这个环境的搭建 ...
- 《天书夜读:从汇编语言到windows内核编程》十 线程与事件
1)驱动中使用到的线程是系统线程,在system进程中.创建线程API函数:PsCreateSystemThread:结束线程(线程内自行调用)API函数:PsTerminateSystemThrea ...
- 《天书夜读:从汇编语言到windows内核编程》七 内核字符串与内存
1)驱动中的字符串使用如下结构: typedef struct _UNICODE_STRING{ USHORT Length; //字符串的长度(字节数) USHORT MaximumLength; ...
- 《天书夜读:从汇编语言到windows内核编程》三 练习反汇编C语言程序
1) Debug版本算法反汇编,现有如下3×3矩阵相乘的程序: #define SIZE 3 int MyFunction(int a[SIZE][SIZE],int b[SIZE][SIZE],in ...
- 《天书夜读:从汇编语言到windows内核编程》二 C语言的流程与处理
1) Debug与Release的区别:前者称调试版,后者称发行版.调试版基本不优化,而发行版会经过编译器的极致优化,往往与优化前的高级语言执行流程会大相径庭,但是实现的功能是等价的. 2) 如下fo ...
随机推荐
- 上传文件没有写权限Access to the path is denied
Access to the path is denied. asp.net程序目录放在系统盘,ntfs格式. 程序中对cfg.xml有写入操作. 运行的时候出现了这个问题. 在我自己的机器上没有问题 ...
- Maven打包Jar
现状 该项目使用了Maven,并且引入了Spring,包含代码.配置文件.Jar包,使用的是IDEA来作为开发工具,项目的产出物是要打包成一个可运行的Jar包.通过IDEA的打包工具也可以打包成功,只 ...
- 【京东个人中心】——Nodejs/Ajax/HTML5/Mysql爬坑之注册与登录监听
一.引言 在数据库和静态页面都创建好之后,下面就该接着完成后台Node.js监听注册和登录的部分了.这个部分主要使用的技术是:Node.js的Express框架和ajax异步请求.登录和注册的代码实现 ...
- 邮件实现详解(二)------手工体验smtp和pop3协议
上篇博客我们简单介绍了电子邮件的发送和接收过程,对参与其中的邮件服务器,邮件客户端软件,邮件传输协议也有简单的介绍.我们知道电子邮件需要在邮件客户端和邮件服务器之间,以及两个邮件服务器之间进行传递必须 ...
- MySQL的备份与还原以及常用数据库查看命令
MySQL命令行导出数据库: 1,进入MySQL目录下的bin文件夹:cd MySQL中到bin文件夹的目录 如我输入的命令行:cd C:\Program Files\MySQL\MySQL Serv ...
- 客户机中PLSQL DEV访问虚拟机中的ORCLE11g,错误百出!
客户机中PLSQL DEV访问虚拟机中的ORCLE11g,错误百出! 创建时间: 2017/10/14 18:44 作者: CNSIMO 标签: ORACLE 忙了一下午,只有两个字形容:麻烦! ...
- python3.6安装pyspider
win10下安装pyspider 1.pip 我在安装pip的时候默认安装了Pip. 如果没有的话:pip安装 2.PhantomJS PhantomJS 是一个基于 WebKit 的服务器端 Jav ...
- IDoc 基础知识
Application Link Enabling ALE主要为了分布式业务系统而设计的.它可以使业务流程中的每个步骤分布在不同的SAP系统上,系统间可以通过IDoc交互数据.IDoc可以认为是个信封 ...
- C#枚举中使用Flags特性
如果对一个值可以包含多个,那么可以使用枚举,加上Flags 本文告诉大家如何写一个 Flags. 在写前,需要知道一些基础知识,取反.或.与,如果不知道的话,请去看看基础. 当然,这些太复杂了,我也不 ...
- 使用bitset实现毫秒级查询(二)
在上一篇中我们了解了bitset索引的基本用法,本篇开始学习bitset索引更新及一些复杂查询. 1.bitset索引更新 因为我们的数据是在系统启动时全部加载进内存,所以当数据库数据发生变化时要 ...