29、定时器

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

1KeWaitForSingleObject

2KeDelayExecutionThread KeWaitForSingleObject类似,都是强制当前线程进入睡眠状态。

3KeStallExecutionProcessor 其让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

4IRP超时处理

规定时间内对某一设备的操作没有反应,则可以取消该操作。应用程序中使用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 }

 

示例代码 P290

posted @ 2010-11-14 20:19  浪里飞  阅读(2069)  评论(0编辑  收藏  举报