Windows编程—Windows驱动中定时器的使用

文章目录

  • Windows编程—Windows驱动中定时器的使用
  • 前言
  • 代码
    • 简单版
    • 升级版
  • 程序效果

Windows编程—Windows驱动中定时器的使用

前言

定时器操作是应用编程中非常常见的操作,同样的在Windows内核驱动编程中也有对应的API。在Windows应用编程中使用的是SetTimer进行定时器编程,在Windows驱动开发中也有对应的API。主要用的下面3个API。


// 1.初始化定时器
VOID 
  KeInitializeTimer(
    // 指向要初始化的定时器,调用者分配空间
    IN PKTIMER  Timer
    );

// 2.初始化dpc结构体对应,可以指定定时器回调函数
VOID 
  KeInitializeDpc(
    // 指向KDPC结构体指针,调用者必须自己分配持久的内存空间
    IN PRKDPC  Dpc,
    // 定时器回调函数,函数原型 CustomDpc 
    IN PKDEFERRED_ROUTINE  DeferredRoutine,
    // 回调函数上下文参数,会在调用定时器回调函数时作为参数2传入
    IN PVOID  DeferredContext
    );

// 3.启动定时器
BOOLEAN 
  KeSetTimer(
    // 已经初始化好的定时器
    IN PKTIMER  Timer,
    // 延时执行回调函数的相对时间 或者 绝对时间,相对时间使用负数(单位为100ns),正数会被视为绝对时间 该时间依赖操作系统时间
    IN LARGE_INTEGER  DueTime,
    // 指向dpc结构体的指针,主要用于和定时器回调函数关联的
    IN PKDPC  Dpc OPTIONAL
    );


// CustomDpc原型
KDEFERRED_ROUTINE CustomDpc;
VOID
  CustomDpc(
    __in struct _KDPC  *Dpc,
    __in_opt PVOID  DeferredContext,
    __in_opt PVOID  SystemArgument1,
    __in_opt PVOID  SystemArgument2
    )
  {...}

代码

简单版

按照参数要求 可以写个简单版的定时器,需要分配空间的 都用全局变量 提前分配好。代码中有详细注释。

MyTimer.c

#include 
#include 
#pragma ("Ntstrsafe.lib",lib)
	

VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("02-DriverUnload enter\r\n");
}

PWCHAR MyCurTimeStr()
{
    LARGE_INTEGER snow,now;
    TIME_FIELDS now_fields;
    static WCHAR time_str[32] = { 0 };
    // 获得标准时间
    KeQuerySystemTime(&snow);
    // 转换为当地时间
    ExSystemTimeToLocalTime(&snow,&now);
    // 转换为人类可以理解的时间要素
    RtlTimeToTimeFields(&now,&now_fields);
    // 打印到字符串中
    RtlStringCchPrintfW(
    time_str,
    32*2,
    L"%4d-%d-%2d %2d:%2d:%d",
    now_fields.Year,now_fields.Month,now_fields.Day,
    now_fields.Hour,now_fields.Minute,now_fields.Second);
    return time_str;
}

// 这些都可以封装在一个构体中
KTIMER my_timer;
KDPC my_dpc;
unsigned int timer_count = 5; // 定时器回调函数执行次数
unsigned int timer_interval = 5000 ; // 定时器执行间隔时间ms


VOID MyCustomDpc(
    IN struct _KDPC *Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
)
{
	PKTIMER pTimer = (PKTIMER)DeferredContext;
	LARGE_INTEGER time;
	static int i = 1;
	
	time.QuadPart = -10000; 
	time.QuadPart *= timer_interval;
	if( --timer_count > 0)
	{
		// 继续启动定时器
		KeSetTimer(pTimer,time,&my_dpc);
	}
	DbgPrint("%ws MyCustomDpc enter %d \r\n",MyCurTimeStr(),i++);
}
	


// DriverEntry,入口函数。
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
	// 设置断点
#if DBG
    //   _asm int 3
#endif
	// 注意所有的变量要声明在函数的最开头
	LARGE_INTEGER time;

	DbgPrint("02-DriverEntry enter\r\n");
	
	// 1.初始化定时器
	KeInitializeTimer(&my_timer);
	
	// 2.初始化Dpc,也就是初始化 延时执行的回调函数结构
	// 将my_timer作为定时回调MyCustomDpc的context,方便执行完后继续下一次定时。
	// 所以这可以继续封装,可以将需要的封装成一个结构体往里面传,然后在回调函数中可以取到
	KeInitializeDpc(&my_dpc,MyCustomDpc,&my_timer); 
	
	
	// 延时单位为100ns,1ms = 1000us = 10000 00ns 
	// 此时延时1ms,且必须为负数,负数才认为是相对时间否则认为是绝对时间
	time.QuadPart = -10000; 
	time.QuadPart *= timer_interval;
	
	// 3.启动定时器
	KeSetTimer(&my_timer,time,&my_dpc);
	
	
	driver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

升级版

自己简单封装一下,代码中有详细注释。MyTimer.c

#include 
#include 
#pragma ("Ntstrsafe.lib",lib)
	

VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("03—DriverUnload enter\r\n");
}

PWCHAR MyCurTimeStr()
{
    LARGE_INTEGER snow,now;
    TIME_FIELDS now_fields;
    static WCHAR time_str[32] = { 0 };
    // 获得标准时间
    KeQuerySystemTime(&snow);
    // 转换为当地时间
    ExSystemTimeToLocalTime(&snow,&now);
    // 转换为人类可以理解的时间要素
    RtlTimeToTimeFields(&now,&now_fields);
    // 打印到字符串中
    RtlStringCchPrintfW(
    time_str,
    32*2,
    L"%4d-%d-%2d %2d:%2d:%d",
    now_fields.Year,now_fields.Month,now_fields.Day,
    now_fields.Hour,now_fields.Minute,now_fields.Second);
    return time_str;
}

// 定义自己封装的定时器timer
typedef struct MyTimer
{
	KTIMER m_timer; // timer结构 
	KDPC m_dpc;		// dpc结构
	PKDEFERRED_ROUTINE  m_func;	// 定时触发的回调函数
	unsigned int m_count; 		// 执行次数
	unsigned int m_interval;	// 间隔时间,单位ms
}MyTimer,*PMyTimer;


// 1.定时器相关内容初始化
VOID MyTimerInit(
	PMyTimer timer,			// 初始化的定时结构体
	PKDEFERRED_ROUTINE  func,// 定时器回调函数
	unsigned int count, 	// 定时器执行次数
	unsigned int interval 	// 执行间隔,单位ms
	)
{
	timer->m_func = func;
	timer->m_count = count;
	timer->m_interval = interval;
	KeInitializeTimer(&timer->m_timer);
	KeInitializeDpc(&timer->m_dpc,timer->m_func,timer);
}


// 2.启动定时器
VOID MyTimerSet(PMyTimer timer)
{
	LARGE_INTEGER time;
	time.QuadPart = -10000;
	time.QuadPart *= timer->m_interval;
	KeSetTimer(&timer->m_timer,time,&timer->m_dpc);
}


// 定时器回调函数
VOID MyCustomDpc(
    IN struct _KDPC *Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
)
{
	PMyTimer pTimer = (PMyTimer)DeferredContext;
	static int i = 1;
	
	if( --pTimer->m_count > 0)
	{
		// 继续启动定时器
		MyTimerSet(pTimer);
	}
	
	DbgPrint("%ws MyCustomDpc enter %d \r\n",MyCurTimeStr(),i++);
}
	
MyTimer g_timer;

// DriverEntry,入口函数。
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
	// 设置断点
#if DBG
       // _asm int 3
#endif
	// 1.定时器相关初始化
	MyTimerInit(&g_timer,MyCustomDpc,5,5000);
	// 2.启动定时器
	MyTimerSet(&g_timer);
	
	DbgPrint("03-DriverEntry enter\r\n");
	driver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

程序效果

2个示例程序运行效果。
Windows编程—Windows驱动中定时器的使用_第1张图片

你可能感兴趣的:(【Windows编程】,#,【Windows驱动】,Windows编程,Windows驱动,KeSetTimer,Windows内核驱动开发)