一般两种方法使用/设置定时器,一种是使用I/O定时器例程,一种是使用DPC例程。
1、定时器的实现
1)使用I/O定时器例程
NTSTATUS
IoInitializeTimer(
IN PDEVICE_OBJECT DeviceObject,
IN PIO_TIMER_ROUTINE TimerRoutine,
IN PVOID Context
);
IoStartTimer
IoStopTimer
开启定时器后,每隔1s系统调用一次定时器例程。TimerRoutine运行在DISPATCH_LEVEL级别,因此不能有分页内存。另外I/O定时器是运行在任意线程的,不能直接使用应用程序的内存地址。

1 // .h
  2  //设定3秒间隔时间
  3  #define TIMER_OUT    3
  4
  5 typedef struct _DEVICE_EXTENSION {
  6     PDEVICE_OBJECT pDevice;
  7     UNICODE_STRING ustrDeviceName;    //设备名称
  8      UNICODE_STRING ustrSymLinkName;    //符号链接名
  9  
 10     LONG lTimerCount;
 11 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 12  //.cpp
 13  #pragma LOCKEDCODE
 14 VOID OnTimer(
 15     IN PDEVICE_OBJECT DeviceObject,
 16     IN PVOID Context)
 17 {
 18     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
 19         DeviceObject->DeviceExtension;
 20     KdPrint(("Enter OnTimer!\n"));
 21
 22     //将计数器自锁减一
 23     InterlockedDecrement(&pDevExt->lTimerCount);
 24    
 25     //如果计数器减到0,重新编程TIMER_OUT,整个过程是互锁运算
 26     LONG previousCount = InterlockedCompareExchange(&pDevExt->lTimerCount,TIMER_OUT,0);
 27
 28     //每隔三秒,计数器一个循环,输出以下log
 29     if (previousCount==0)
 30     {
 31         KdPrint(("%d seconds time out!\n",TIMER_OUT));
 32     }
 33
 34     //证明该线程运行在任意线程上下文的
 35     PEPROCESS pEProcess = IoGetCurrentProcess();
 36   
 37     PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);//即可得到用户进程
 38
 39     KdPrint(("The current process is %s\n",ProcessName));
 40 }
 41
 42
 43 /************************************************************************
 44 * 函数名称:CreateDevice
 45 * 功能描述:初始化设备对象
 46 * 参数列表:
 47       pDriverObject:从I/O管理器中传进来的驱动对象
 48 * 返回 值:返回初始化状态
 49 *************************************************************************/
 50 #pragma INITCODE
 51 NTSTATUS CreateDevice (
 52         IN PDRIVER_OBJECT    pDriverObject)
 53 {
 54     NTSTATUS status;
 55     PDEVICE_OBJECT pDevObj;
 56     PDEVICE_EXTENSION pDevExt;
 57    
 58     //创建设备名称
 59     UNICODE_STRING devName;
 60     RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
 61    
 62     //创建设备
 63     status = IoCreateDevice( pDriverObject,
 64                         sizeof(DEVICE_EXTENSION),
 65                         &(UNICODE_STRING)devName,
 66                         FILE_DEVICE_UNKNOWN,
 67                         0, TRUE,
 68                         &pDevObj );
 69     if (!NT_SUCCESS(status))
 70         return status;
 71
 72     pDevObj->Flags |= DO_DIRECT_IO;
 73     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
 74     pDevExt->pDevice = pDevObj;
 75     pDevExt->ustrDeviceName = devName;
 76
 77     IoInitializeTimer(pDevObj,OnTimer,NULL);
 78
 79     //创建符号链接
 80     UNICODE_STRING symLinkName;
 81     RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
 82     pDevExt->ustrSymLinkName = symLinkName;
 83     status = IoCreateSymbolicLink( &symLinkName,&devName );
 84     if (!NT_SUCCESS(status))
 85     {
 86         IoDeleteDevice( pDevObj );
 87         return status;
 88     }
 89     return STATUS_SUCCESS;
 90 }
 91 #pragma PAGEDCODE
 92 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
 93                                  IN PIRP pIrp)
 94 {
 95     NTSTATUS status = STATUS_SUCCESS;
 96     KdPrint(("Enter HelloDDKDeviceIOControl\n"));
 97
 98     //得到当前堆栈
 99     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
100     //得到输入缓冲区大小
101     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
102     //得到输出缓冲区大小
103     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
104     //得到IOCTL码
105     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
106
107     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
108         pDevObj->DeviceExtension;
109
110     ULONG info = 0;
111
112     switch (code)
113     {                        // process request
114         case IOCTL_START_TIMER:
115         {
116             KdPrint(("IOCTL_START_TIMER\n"));
117             pDevExt->lTimerCount = TIMER_OUT;
118             IoStartTimer(pDevObj);
119             break;
120         }
121         case IOCTL_STOP:
122         {
123             KdPrint(("IOCTL_STOP\n"));
124             IoStopTimer(pDevObj);
125             break;
126         }
127         default:
128             status = STATUS_INVALID_VARIANT;
129     }
130
131     // 完成IRP
132     pIrp->IoStatus.Status = status;
133     pIrp->IoStatus.Information = info;    // bytes xfered
134     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
135
136     KdPrint(("Leave HelloDDKDeviceIOControl\n"));
137
138     return status;
139 }

1 #include <windows.h>
 2 #include <stdio.h>
 3 //使用CTL_CODE必须加入winioctl.h
 4 #include <winioctl.h>
 5 #include "..\NT_Driver\Ioctls.h"
 6
 7 int main()
 8 {
 9     HANDLE hDevice =
10         CreateFile("\\\\.\\HelloDDK",
11                     GENERIC_READ | GENERIC_WRITE,
12                     0,        // share mode none
13                     NULL,    // no security
14                     OPEN_EXISTING,
15                     FILE_ATTRIBUTE_NORMAL,
16                     NULL );        // no template
17
18     if (hDevice == INVALID_HANDLE_VALUE)
19     {
20         printf("Failed to obtain file handle to device: "
21             "%s with Win32 error code: %d\n",
22             "MyWDMDevice", GetLastError() );
23         return 1;
24     }
25
26     DWORD dwOutput;
27
28     DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);
29
30     Sleep(10000);
31
32      DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, 0, &dwOutput, NULL);
33
34     CloseHandle(hDevice);
35
36     return 0;
37 }

示例代码 P278

2)使用DPC例程
DPC定时器内部使用定时器对象KTIMER,当指定的时间间隔到达后,OS会将一个DPC例程插入DPC队列。
KeInitializeTimer
KeInitializeDpc
BOOLEAN
KeSetTimer(
IN PKTIMER Timer,
IN LARGE_INTEGER DueTime, //设定时间间隔
IN PKDPC Dpc OPTIONAL
);
如果DueTime为正数,则该时间表示从1601/01/01到触发DPC例程的那个时刻,单位是100ns,如果为负数,意味着间隔多长时间,单位也是100ns。
在调用KeSetTimer后,触发一次DPC例程,如果想周期触发,则需要在DPC触发后,再次调用KeSetTimer。
KeInitializeDpc

1 //.h
  2 //设定3秒间隔时间
  3 #define TIMER_OUT    3
  4
  5 typedef struct _DEVICE_EXTENSION {
  6     PDEVICE_OBJECT pDevice;
  7     UNICODE_STRING ustrDeviceName;    //设备名称
  8     UNICODE_STRING ustrSymLinkName;    //符号链接名
  9
 10     KDPC pollingDPC;    // 存储DPC对象
 11     KTIMER pollingTimer;// 存储计时器对象
 12     LARGE_INTEGER pollingInterval;    // 记录计时器间隔时间
 13 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 14 //.cpp
 15 #pragma LOCKEDCODE
 16 VOID PollingTimerDpc( IN PKDPC pDpc,
 17                       IN PVOID pContext,
 18                       IN PVOID SysArg1,
 19                       IN PVOID SysArg2 )
 20 {
 21     PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
 22     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
 23     KeSetTimer(
 24         &pdx->pollingTimer,
 25         pdx->pollingInterval,
 26         &pdx->pollingDPC );
 27     KdPrint(("PollingTimerDpc\n"));
 28
 29     //检验是运行在任意线程上下文
 30     PEPROCESS pEProcess = IoGetCurrentProcess();
 31   
 32     PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
 33
 34     KdPrint(("%s\n",ProcessName));
 35 }
 36 /************************************************************************
 37 * 函数名称:CreateDevice
 38 * 功能描述:初始化设备对象
 39 * 参数列表:
 40       pDriverObject:从I/O管理器中传进来的驱动对象
 41 * 返回 值:返回初始化状态
 42 *************************************************************************/
 43 #pragma INITCODE
 44 NTSTATUS CreateDevice (
 45         IN PDRIVER_OBJECT    pDriverObject)
 46 {
 47     NTSTATUS status;
 48     PDEVICE_OBJECT pDevObj;
 49     PDEVICE_EXTENSION pDevExt;
 50    
 51     //创建设备名称
 52     UNICODE_STRING devName;
 53     RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
 54    
 55     //创建设备
 56     status = IoCreateDevice( pDriverObject,
 57                         sizeof(DEVICE_EXTENSION),
 58                         &(UNICODE_STRING)devName,
 59                         FILE_DEVICE_UNKNOWN,
 60                         0, TRUE,
 61                         &pDevObj );
 62     if (!NT_SUCCESS(status))
 63         return status;
 64
 65     pDevObj->Flags |= DO_DIRECT_IO;
 66     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
 67     pDevExt->pDevice = pDevObj;
 68     pDevExt->ustrDeviceName = devName;
 69
 70     KeInitializeTimer( &pDevExt->pollingTimer );
 71
 72     KeInitializeDpc( &pDevExt->pollingDPC,
 73                         PollingTimerDpc,
 74                         (PVOID) pDevObj );
 75
 76     //创建符号链接
 77     UNICODE_STRING symLinkName;
 78     RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
 79     pDevExt->ustrSymLinkName = symLinkName;
 80     status = IoCreateSymbolicLink( &symLinkName,&devName );
 81     if (!NT_SUCCESS(status))
 82     {
 83         IoDeleteDevice( pDevObj );
 84         return status;
 85     }
 86     return STATUS_SUCCESS;
 87 }
 88 #pragma PAGEDCODE
 89 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
 90                                  IN PIRP pIrp)
 91 {
 92     NTSTATUS status = STATUS_SUCCESS;
 93     KdPrint(("Enter HelloDDKDeviceIOControl\n"));
 94
 95     //得到当前堆栈
 96     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
 97     //得到输入缓冲区大小
 98     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
 99     //得到输出缓冲区大小
100     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
101     //得到IOCTL码
102     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
103
104     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
105         pDevObj->DeviceExtension;
106
107     ULONG info = 0;
108
109     switch (code)
110     {                        // process request
111         case IOCTL_START_TIMER:
112         {
113             KdPrint(("IOCTL_START_TIMER!\n"));
114
115             //从用户模式传进来的超时
116             ULONG ulMircoSeconds = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
117
118             pDevExt->pollingInterval = RtlConvertLongToLargeInteger( ulMircoSeconds * -10 );
119
120             KeSetTimer(
121                 &pDevExt->pollingTimer,
122                 pDevExt->pollingInterval,
123                 &pDevExt->pollingDPC );
124             break;
125         }
126         case IOCTL_STOP_TIMER:
127         {
128             KdPrint(("IOCTL_STOP_TIMER!\n"));
129
130             KeCancelTimer(&pDevExt->pollingTimer);
131
132             break;
133         }
134         default:
135             status = STATUS_INVALID_VARIANT;
136     }
137
138     // 完成IRP
139     pIrp->IoStatus.Status = status;
140     pIrp->IoStatus.Information = info;    // bytes xfered
141     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
142
143     KdPrint(("Leave HelloDDKDeviceIOControl\n"));
144
145     return status;
146 }
147 //main
148 #include <windows.h>
149 #include <stdio.h>
150 //使用CTL_CODE必须加入winioctl.h
151 #include <winioctl.h>
152 #include "..\NT_Driver\Ioctls.h"
153
154 int main()
155 {
156     HANDLE hDevice =
157         CreateFile("\\\\.\\HelloDDK",
158                     GENERIC_READ | GENERIC_WRITE,
159                     0,        // share mode none
160                     NULL,    // no security
161                     OPEN_EXISTING,
162                     FILE_ATTRIBUTE_NORMAL,
163                     NULL );        // no template
164
165     if (hDevice == INVALID_HANDLE_VALUE)
166     {
167         printf("Failed to obtain file handle to device: "
168             "%s with Win32 error code: %d\n",
169             "MyWDMDevice", GetLastError() );
170         return 1;
171     }
172
173     DWORD dwOutput;
174     DWORD dwMircoSeconds = 1000*1000*2;
175
176     DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
177
178     Sleep(10000);
179
180      DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);
181
182     CloseHandle(hDevice);
183
184     return 0;
185 }

示例代码 P282

DPC例程运行在DISPATCH_LEVEL级别。
2、等待
1)KeWaitForSingleObject
2)KeDelayExecutionThread 与KeWaitForSingleObject类似,都是强制当前线程进入睡眠状态。
3)KeStallExecutionProcessor 其让CPU处于忙等待,而不是睡眠,类似于自旋锁。浪费CPU时间,不宜超过50us。
4)使用定时器
定时器对象同其它内核对象一样,也有两个状态:激发与未激发态。初始化时未激发态,使用KeSetTimer后,经过指定时间后,变成激发态,可以用KeWaitForSingleObject来进行等待。

1 #pragma PAGEDCODE
  2 VOID WaitMicroSecond1(ULONG ulMircoSecond)
  3 {
  4     KEVENT kEvent;
  5
  6     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
  7
  8     //初始化一个未激发的内核事件
  9     KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE);
 10
 11     //等待时间的单位是100纳秒,将微秒转换成这个单位
 12     //负数代表是从此刻到未来的某个时刻
 13     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);
 14
 15     //在经过timeout后,线程继续运行
 16     KeWaitForSingleObject(&kEvent,
 17         Executive,
 18         KernelMode,
 19         FALSE,
 20         &timeout);
 21
 22     KdPrint(("Thread is running again!\n"));
 23 }
 24
 25 #pragma PAGEDCODE
 26 VOID WaitMicroSecond2(ULONG ulMircoSecond)
 27 {
 28     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
 29
 30     //等待时间的单位是100纳秒,将微秒转换成这个单位
 31     //负数代表是从此刻到未来的某个时刻
 32     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);
 33
 34     //此种方法类似于KeWaitForSingleObject
 35     //将当前线程进入睡眠状态,间隔时间到转入运行状态
 36     KeDelayExecutionThread(KernelMode,FALSE,&timeout);
 37
 38     KdPrint(("Thread is running again!\n"));
 39 }
 40
 41 #pragma PAGEDCODE
 42 VOID WaitMicroSecond3(ULONG ulMircoSecond)
 43 {
 44     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
 45
 46     //忙等待,此种方法属于忙等待,比较浪费CPU时间
 47     //因此使用该方法不宜超过50微秒
 48     KeStallExecutionProcessor(ulMircoSecond);
 49
 50     KdPrint(("Thread is running again!\n"));
 51 }
 52
 53 #pragma PAGEDCODE
 54 VOID WaitMicroSecond4(ULONG ulMircoSecond)
 55 {
 56     //使用计时器
 57
 58     KTIMER kTimer;//内核计时器
 59
 60     //初始化计时器
 61     KeInitializeTimer(&kTimer);
 62
 63     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * -10 );
 64
 65     //注意这个计时器没有和DPC对象关联
 66     KeSetTimer(&kTimer,timeout,    NULL);
 67     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
 68
 69     KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL);
 70
 71     KdPrint(("Thread is running again!\n"));
 72 }
 73 #pragma PAGEDCODE
 74 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
 75                                  IN PIRP pIrp)
 76 {
 77     NTSTATUS status = STATUS_SUCCESS;
 78     KdPrint(("Enter HelloDDKDeviceIOControl\n"));
 79
 80     //得到当前堆栈
 81     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
 82     //得到输入缓冲区大小
 83     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
 84     //得到输出缓冲区大小
 85     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
 86     //得到IOCTL码
 87     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
 88
 89     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
 90         pDevObj->DeviceExtension;
 91
 92     ULONG info = 0;
 93
 94     //得到用户程序传进来的微秒数
 95     ULONG ulMircoSecond = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
 96
 97     switch (code)
 98     {                        // process request
 99         case IOCTL_WAIT_METHOD1:
100         {
101             KdPrint(("IOCTL_WAIT_METHOD1\n"));
102             WaitMicroSecond1(ulMircoSecond);
103             break;
104         }
105         case IOCTL_WAIT_METHOD2:
106         {
107             KdPrint(("IOCTL_WAIT_METHOD2\n"));
108             WaitMicroSecond2(ulMircoSecond);
109             break;
110         }
111         case IOCTL_WAIT_METHOD3:
112         {
113             KdPrint(("IOCTL_WAIT_METHOD3\n"));
114             WaitMicroSecond3(ulMircoSecond);
115             break;
116         }
117         case IOCTL_WAIT_METHOD4:
118         {
119             KdPrint(("IOCTL_WAIT_METHOD4\n"));
120             WaitMicroSecond4(ulMircoSecond);
121             break;
122         }
123         default:
124             status = STATUS_INVALID_VARIANT;
125     }
126
127     // 完成IRP
128     pIrp->IoStatus.Status = status;
129     pIrp->IoStatus.Information = info;    // bytes xfered
130     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
131
132     KdPrint(("Leave HelloDDKDeviceIOControl\n"));
133
134     return status;
135 }
136 //.cpp
137 #include <windows.h>
138 #include <stdio.h>
139 //使用CTL_CODE必须加入winioctl.h
140 #include <winioctl.h>
141 #include "..\NT_Driver\Ioctls.h"
142
143 int main()
144 {
145     HANDLE hDevice =
146         CreateFile("\\\\.\\HelloDDK",
147                     GENERIC_READ | GENERIC_WRITE,
148                     0,        // share mode none
149                     NULL,    // no security
150                     OPEN_EXISTING,
151                     FILE_ATTRIBUTE_NORMAL,
152                     NULL );        // no template
153
154     if (hDevice == INVALID_HANDLE_VALUE)
155     {
156         printf("Failed to obtain file handle to device: "
157             "%s with Win32 error code: %d\n",
158             "MyDDKDevice", GetLastError() );
159         return 1;
160     }
161
162     DWORD dwOutput;
163
164     DWORD dwMicroSecond = 1000;
165     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD1, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
166     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD2, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
167     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD3, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
168     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD4, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
169
170     CloseHandle(hDevice);
171
172     return 0;
173 }

示例代码 P286

3、其它相关函数
获取当前系统时间:KeQuerySystemTime
This value is computed for the GMT time zone. To adjust this value for the local time zone use ExSystemTimeToLocalTime.(在控制面板中设置)
RtlTimeFieldsToTime converts TIME_FIELDS information to a system time value
RtlTimeToTimeFields

1 /************************************************************************
  2 * 函数名称:DriverEntry
  3 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
  4 * 参数列表:
  5       pDriverObject:从I/O管理器中传进来的驱动对象
  6       pRegistryPath:驱动程序在注册表的中的路径
  7 * 返回 值:返回初始化驱动状态
  8 *************************************************************************/
  9 #pragma INITCODE
 10 extern "C" NTSTATUS DriverEntry (
 11             IN PDRIVER_OBJECT pDriverObject,
 12             IN PUNICODE_STRING pRegistryPath    )
 13 {
 14     NTSTATUS status;
 15     KdPrint(("Enter DriverEntry\n"));
 16
 17     //设置卸载函数
 18     pDriverObject->DriverUnload = HelloDDKUnload;
 19
 20     //设置派遣函数
 21     for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i)
 22         pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin;
 23
 24     pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
 25    
 26     //创建驱动设备对象
 27     status = CreateDevice(pDriverObject);
 28
 29     KdPrint(("Leave DriverEntry\n"));
 30     return status;
 31 }
 32 #pragma PAGEDCODE
 33 VOID Time_Test()
 34 {
 35     LARGE_INTEGER current_system_time;
 36     //得到当前系统时间
 37     KeQuerySystemTime(&current_system_time);
 38
 39     LARGE_INTEGER current_local_time;
 40     //从系统时间转换成当地时区时间
 41     ExSystemTimeToLocalTime(&current_system_time,&current_local_time);
 42
 43     TIME_FIELDS current_time_info;
 44     //由当地时区时间得到月日年信息
 45     RtlTimeToTimeFields(&current_local_time,&current_time_info);
 46
 47     //显示年月日等信息
 48     KdPrint(("Current year:%d\n",current_time_info.Year));
 49     KdPrint(("Current month:%d\n",current_time_info.Month));
 50     KdPrint(("Current day:%d\n",current_time_info.Day));
 51     KdPrint(("Current Hour:%d\n",current_time_info.Hour));
 52     KdPrint(("Current Minute:%d\n",current_time_info.Minute));
 53     KdPrint(("Current Second:%d\n",current_time_info.Second));
 54     KdPrint(("Current Milliseconds:%d\n",current_time_info.Milliseconds));
 55     KdPrint(("Current Weekday:%d\n",current_time_info.Weekday));
 56 }
 57
 58 #pragma PAGEDCODE
 59 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
 60                                  IN PIRP pIrp)
 61 {
 62     NTSTATUS status = STATUS_SUCCESS;
 63     KdPrint(("Enter HelloDDKDeviceIOControl\n"));
 64
 65     //得到当前堆栈
 66     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
 67     //得到输入缓冲区大小
 68     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
 69     //得到输出缓冲区大小
 70     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
 71     //得到IOCTL码
 72     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
 73
 74     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
 75         pDevObj->DeviceExtension;
 76
 77     ULONG info = 0;
 78
 79     switch (code)
 80     {                        // process request
 81         case IOCTL_TIME_TEST:
 82         {
 83             KdPrint(("IOCTL_TIME_TEST\n"));
 84             Time_Test();
 85             break;
 86         }
 87         default:
 88             status = STATUS_INVALID_VARIANT;
 89     }
 90
 91     // 完成IRP
 92     pIrp->IoStatus.Status = status;
 93     pIrp->IoStatus.Information = info;    // bytes xfered
 94     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
 95
 96     KdPrint(("Leave HelloDDKDeviceIOControl\n"));
 97
 98     return status;
 99 }
100
101 DWORD dwOutput;
102 DeviceIoControl(hDevice, IOCTL_TIME_TEST, NULL, 0, NULL, 0, &dwOutput, NULL);
103 CloseHandle(hDevice);

示例代码 P288

4、IRP超时处理
规定时间内对某一设备的操作没有反应,则可以取消该操作。应用程序中使用CancelIo,驱动中用IoCancelIrp,来取消操作。也可以通过设置IRP超时,来取消IRO,这时进入IRP取消例程。
1)初始个定时器和DPC例程,进行关联。
2)操作IRP前,开户定时器,超时进入DPC例程。
3)如果超时前结束该IRP操作,则应取消定时器。

1 typedef struct _DEVICE_EXTENSION {
  2     PDEVICE_OBJECT pDevice;
  3     UNICODE_STRING ustrDeviceName;    //设备名称
  4     UNICODE_STRING ustrSymLinkName;    //符号链接名
  5
  6     KDPC pollingDPC;    // 存储DPC对象
  7     KTIMER pollingTimer;// 存储计时器对象
  8     PIRP currentPendingIRP;//记录当前挂起的IRP
  9 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 10
 11 pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead;
 12
 13 #pragma LOCKEDCODE
 14 VOID OnTimerDpc( IN PKDPC pDpc,
 15                       IN PVOID pContext,
 16                       IN PVOID SysArg1,
 17                       IN PVOID SysArg2 )
 18 {
 19     PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
 20     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
 21
 22     PIRP currentPendingIRP = pdx->currentPendingIRP;
 23
 24     KdPrint(("Cancel the current pending irp!\n"));
 25
 26     //设置完成状态为STATUS_CANCELLED
 27      currentPendingIRP->IoStatus.Status = STATUS_CANCELLED;
 28      currentPendingIRP->IoStatus.Information = 0;    // bytes xfered
 29      IoCompleteRequest( currentPendingIRP, IO_NO_INCREMENT );
 30 }
 31
 32 /************************************************************************
 33 * 函数名称:CreateDevice
 34 * 功能描述:初始化设备对象
 35 * 参数列表:
 36       pDriverObject:从I/O管理器中传进来的驱动对象
 37 * 返回 值:返回初始化状态
 38 *************************************************************************/
 39 #pragma INITCODE
 40 NTSTATUS CreateDevice (
 41         IN PDRIVER_OBJECT    pDriverObject)
 42 {
 43     NTSTATUS status;
 44     PDEVICE_OBJECT pDevObj;
 45     PDEVICE_EXTENSION pDevExt;
 46    
 47     //创建设备名称
 48     UNICODE_STRING devName;
 49     RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
 50    
 51     //创建设备
 52     status = IoCreateDevice( pDriverObject,
 53                         sizeof(DEVICE_EXTENSION),
 54                         &(UNICODE_STRING)devName,
 55                         FILE_DEVICE_UNKNOWN,
 56                         0, TRUE,
 57                         &pDevObj );
 58     if (!NT_SUCCESS(status))
 59         return status;
 60
 61     pDevObj->Flags |= DO_BUFFERED_IO;
 62     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
 63     pDevExt->pDevice = pDevObj;
 64     pDevExt->ustrDeviceName = devName;
 65
 66     KeInitializeTimer( &pDevExt->pollingTimer );
 67
 68     KeInitializeDpc( &pDevExt->pollingDPC,
 69                         OnTimerDpc,
 70                         (PVOID) pDevObj );
 71
 72     //创建符号链接
 73     UNICODE_STRING symLinkName;
 74     RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
 75     pDevExt->ustrSymLinkName = symLinkName;
 76     status = IoCreateSymbolicLink( &symLinkName,&devName );
 77     if (!NT_SUCCESS(status))
 78     {
 79         IoDeleteDevice( pDevObj );
 80         return status;
 81     }
 82     return STATUS_SUCCESS;
 83 }
 84
 85 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
 86                                  IN PIRP pIrp)
 87 {
 88     KdPrint(("Enter HelloDDKRead\n"));
 89
 90     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
 91             pDevObj->DeviceExtension;
 92
 93     //将IRP设置为挂起
 94     IoMarkIrpPending(pIrp);
 95
 96     //将挂起的IRP记录下来
 97     pDevExt->currentPendingIRP = pIrp;
 98
 99     //定义3秒的超时
100     ULONG ulMicroSecond = 3000000;
101
102     //将32位整数转化成64位整数
103     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMicroSecond);
104    
105     KeSetTimer(
106         &pDevExt->pollingTimer,
107         timeout,
108         &pDevExt->pollingDPC );
109
110     KdPrint(("Leave HelloDDKRead\n"));
111
112     //返回pending状态
113     return STATUS_PENDING;
114 }
115
116 //main
117 #include <windows.h>
118 #include <stdio.h>
119 #include <process.h>
120
121 int main()
122 {
123     HANDLE hDevice =
124         CreateFile("\\\\.\\HelloDDK",
125                     GENERIC_READ | GENERIC_WRITE,
126                     FILE_SHARE_READ,
127                     NULL,
128                     OPEN_EXISTING,
129                     FILE_ATTRIBUTE_NORMAL,
130                     NULL );
131
132     if (hDevice == INVALID_HANDLE_VALUE)
133     {
134         printf("Open Device failed!");
135         return 1;
136     }
137
138     DWORD dwRead;
139
140     //如果读IRP没有被完成,ReadFile一直都不会退出!
141     ReadFile(hDevice,NULL,0,&dwRead,NULL);
142    
143     ReadFile(hDevice,NULL,0,&dwRead,NULL);
144
145     CloseHandle(hDevice);
146
147     return 0;
148 }

Timer和DPC的更多相关文章

  1. 关于DPC和workitem的简单用法

    这个随笔是记录我半个月左右的时间,从想法到查资料请教,以及到实践的成果. 我想实现的是,隔定时时间写文件,本以为调用写的函数就可以实现了,结果各种BSOD,IRQL_NOT_LESS_OR_EQUAL ...

  2. Bypassing PatchGuard on Windows x64

    [说明] 1.  本文是意译,加之本人英文水平有限.windows底层技术属菜鸟级别,本文与原文存在一定误差,请多包涵. 2.  由于内容较多,从word拷贝过来排版就乱了.故你也可以下载附件. 3. ...

  3. 浅谈DPCHookSSDT和RemoveDPC

    最近学了DPC这一对,把Win7 32位和64位都做了,查阅了大量的资料,并且进行了大量调试,理一下思路,为了后面更好的学习. 转载请注明出处:http://www.cnblogs.com/littl ...

  4. x64枚举DPC定时器

    @写在前面      不同于x86,x64的DPC是被加密了的.对于x64DPC的兴趣始于我已经流产的scalpel计划.当时问某牛怎么遍历,得到的答案是“500大洋给代码”.真是R了狗了,好歹小哥我 ...

  5. Windows驱动开发-DPC定时器

    DCP是一种使用更加灵活的定时器,可以对任意间隔时间进行定时.DPC定时器的内部使用了一个定时器对象KTIMER,当你设定了定时器之后,从设定开始起经过这个时间之后操作系统会将一个DPC定时器的例程插 ...

  6. C# - 计时器Timer

    System.Timers.Timer 服务器计时器,允许指定在应用程序中引发事件的重复时间间隔. using System.Timers: // 在应用程序中生成定期事件 public class ...

  7. winform 用户控件、 动态创建添加控件、timer控件、控件联动

    用户控件: 相当于自定义的一个panel 里面可以放各种其他控件,并可以在后台一下调用整个此自定义控件. 使用方法:在项目上右键.添加.用户控件,之后用户控件的编辑与普通容器控件类似.如果要在后台往窗 ...

  8. 【WPF】 Timer与 dispatcherTimer 在wpf中你应该用哪个?

    源:Roboby 1.timer或重复生成timer事件,dispatchertimer是集成到队列中的一个时钟.2.dispatchertimer更适合在wpf中访问UI线程上的元素 3.Dispa ...

  9. STM32F10xxx 之 System tick Timer(SYSTICK Timer)

    背景 研究STM32F10xxx定时器的时候,无意间看到了System tick Timer,于是比较深入的了解下,在此做个记录. 正文 System tick Timer是Cotex-M内核的24位 ...

随机推荐

  1. 给ros安装arbotix simulator仿真环境

    首先下载程序包.编译.安装. cd ~/catkin_ws/src git clone https://github.com/pirobot/rbx1.git cd rbx1 git checkout ...

  2. Noip2000 T3 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  3. Emacs杂谈(一)Emacs环境 c++ 快捷键

    最近头脑发热(抽),重装了电脑,改成linux的ubuntu系统,熟悉一下环境,顺便转载相关emacs知识. //插播一则通知:似乎linux上vector不能用,会内存炸错,若有人可以解答,请用评论 ...

  4. matrix(No.1)operations

  5. addClass, removeClass, toggleClass(从jquery中抠出来)

    <div id="d3" class="cur"></div> var mylibs = (function(){ var rtrim ...

  6. mac系统使用内置的 PHP

    从 OS X 10.0.0 版本开始,PHP 作为 Mac 机的标准配置被提供.在默认的 web 服务器中启用 PHP,只需将 Apache 配置文件 httpd.conf 中的几行配置指令最前面的注 ...

  7. Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. ...

  8. BZOJ 3295 【Cqoi2011】 动态逆序对

    Description 对于序列\(A\),它的逆序对数定义为满足\(i<j\),且\(A_i>A_j\)的数对\((i,j)\)的个数.给\(1\)到\(n\)的一个排列,按照某种顺序依 ...

  9. ios开发--多台电脑共用一个开发证书的方法

    Xcode5 以前的操作步骤是: idp证书如何给另一台机子使用 先在原电脑上用Xcode->Windows->Organizer, 再点击Developer profile, 在其最下面 ...

  10. C#.NET 大型通用信息化系统集成快速开发平台 4.0 版本 - 组织机构的名称编号是否允许重复?

    通常情况下,一个公司内部的部门名称,编号是不可能重复的.但是是在多公司的情况下,很可能有部门名称重复的问题存在,这时需要允许部门名称重复. 例如一个大型IT公司,在2个地区都有研发部或者客户服务部,这 ...