驱动程序中IO定时器的实现详解

IO定时器是DDK提供的一种定时器。使用这种定时器时,每间隔1s系统会调用一次IO定时器例程。
程序员稍加改进,就可以将定时间隔修改为多秒。
如果需要的时间间隔小于1S,那么IO定时器就没办法做到了,就需要用DPC定时器了。
IO定时器的使用之前需要对其进行初始化,初始化的时候使用内核函数IoInitializeTimer。

NTSTATUS  
  IoInitializeTimer( 
    IN PDEVICE_OBJECT  DeviceObject,//关联设备对象指针 
    IN PIO_TIMER_ROUTINE  TimerRoutine,//关联定时器例程,回调函数 
    IN PVOID  Context//这个是传入的参数 
    ); 



其中回调函数的格式如下:
VOID
  IoTimer( 
    __in struct DEVICE_OBJECT  *DeviceObject, 
    __in_opt PVOID  Context 
    ) 
  {...} 



需要说明的是,IO定时器例程运行在DISPATCH_LEVEL级别,因此例程中不能使用分页内存。否则会引起系统崩溃。
另外,IO定时器是运行在任意线程的,不一定是IRP发起的线程中。

下面是演示程序。
1.初始化

1 IoInitializeTimer(pDevObj,OnTimer,NULL); 


2.在设备扩展中加入一个计数变量,这个计数变量负责记录间隔的秒数。

typedef struct _DEVICE_EXTENSION { 
        PDEVICE_OBJECT pDevice; 
        UNICODE_STRING ustrDeviceName;        //设备名称 
        UNICODE_STRING ustrSymLinkName;        //符号链接名 
        LONG lTimerCount;//定时计数 
} DEVICE_EXTENSION, *PDEVICE_EXTENSION; 



3.定义两个IOCTL码,分别是启动定时器和停止定时器的请求。

#define IOCTL_START_TIMER CTL_CODE(\ 
                        FILE_DEVICE_UNKNOWN, \ 
                        0x800, \ 
                        METHOD_BUFFERED, \ 
                        FILE_ANY_ACCESS) 
  
#define IOCTL_STOP CTL_CODE(\ 
                        FILE_DEVICE_UNKNOWN, \ 
                        0x801, \ 
                        METHOD_IN_DIRECT, \ 
                        FILE_ANY_ACCESS) 



在DDK中使用 IoStartTimer  和IoStopTimer  函数用来控制定时器的启动和停止。

VOID 
  IoStartTimer( 
    IN PDEVICE_OBJECT  DeviceObject 
    ); 
VOID 
  IoStopTimer( 
    IN PDEVICE_OBJECT  DeviceObject 
    ); 


 


4.如下为内核层的定时器控制演示程序

 #pragma PAGEDCODE 
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj, 
                                                                 IN PIRP pIrp) 
{ 
        NTSTATUS status = STATUS_SUCCESS; 
        KdPrint(("Enter HelloDDKDeviceIOControl\n")); 
  
        //得到当前堆栈 
        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); 
        //得到输入缓冲区大小 
        ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; 
        //得到输出缓冲区大小 
        ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; 
        //得到IOCTL码 
        ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; 
  
        PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) 
                pDevObj->DeviceExtension; 
  
        ULONG info = 0; 
  
        switch (code) 
        {                                                // process request 
                case IOCTL_START_TIMER: 
                { 
                        KdPrint(("IOCTL_START_TIMER\n")); 
                        pDevExt->lTimerCount = TIMER_OUT; 
                        IoStartTimer(pDevObj); 
                        break; 
                } 
                case IOCTL_STOP: 
                { 
                        KdPrint(("IOCTL_STOP\n")); 
                        IoStopTimer(pDevObj); 
                        break; 
                } 
                default: 
                        status = STATUS_INVALID_VARIANT; 
        } 
  
        // 完成IRP 
        pIrp->IoStatus.Status = status; 
        pIrp->IoStatus.Information = info;        // bytes xfered 
        IoCompleteRequest( pIrp, IO_NO_INCREMENT ); 
  
        KdPrint(("Leave HelloDDKDeviceIOControl\n")); 
  
        return status; 
} 



5.编写定时器例程,下面是定时器例程的演示程序

#pragma LOCKEDCODE 
VOID OnTimer( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PVOID Context) 
{ 
        PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) 
                DeviceObject->DeviceExtension; 
        KdPrint(("Enter OnTimer!\n")); 
  
        //将计数器自锁减一 
        InterlockedDecrement(&pDevExt->lTimerCount); 
          
        //如果计数器减到0,重新编程TIMER_OUT,整个过程是互锁运算 
        LONG previousCount = InterlockedCompareExchange(&pDevExt->lTimerCount,TIMER_OUT,0); 
  
        //每隔三秒,计数器一个循环,输出以下log 
        if (previousCount==0) 
        { 
                KdPrint(("%d seconds time out!\n",TIMER_OUT)); 
        } 
  
        //证明该线程运行在任意线程上下文的 
    PEPROCESS pEProcess = IoGetCurrentProcess(); 
     
    PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);//即可得到用户进程 
  
    KdPrint(("The current process is %s\n",ProcessName)); 
} 


6.编写应用层程序,用于控制定时器的启动和停止

int main() 
{ 
        HANDLE hDevice =  
                CreateFile("\\\\.\\HelloDDK", 
                                        GENERIC_READ | GENERIC_WRITE, 
                                        0,                // share mode none 
                                        NULL,        // no security 
                                        OPEN_EXISTING, 
                                        FILE_ATTRIBUTE_NORMAL, 
                                        NULL );                // no template 
  
        if (hDevice == INVALID_HANDLE_VALUE) 
        { 
                printf("Failed to obtain file handle to device: "
                        "%s with Win32 error code: %d\n", 
                        "MyWDMDevice", GetLastError() ); 
                return 1; 
        } 
  
        DWORD dwOutput; 
  
        DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL); 
  
        Sleep(10000); 
  
         DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, 0, &dwOutput, NULL); 
  
        CloseHandle(hDevice); 
  
        return 0; 
} 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值