Timer和DPC

时间:2023-03-09 21:00:57
Timer和DPC

一般两种方法使用/设置定时器,一种是使用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 }