28、Windows内核编程,IRP的同步(2)
3、StartIo例程
1)系统处理的StartIo
StartIo例程能够保证各个并行的IRP顺序执行,即串行化。
DDK提供一个内部队列,并将IRP用StartIo例程串行化处理。当设备由忙转入空闲状态时,从队列中抽取一个IRP进行处理,并将状态设为忙。一个新的IRP来时,如果设备为忙,则插入到队列当中,如果为空闲,则直接处理。
OS提供kdevice_queue来实现串行化,队列头保存在pDriverObject->DeviceQueue子域中。插入和删除由OS负责。使用这个队列时,需要提供一个叫做StartIo的例程。
pDriverObject->DriverStartIo = HelloDDKStartIO;
这个StartIo例程运行在DISPATCH_LEVEL,不会线程打断的,所以不可分页。派遣函数加入IoStartPacket,就可以把IRP插入到队列中了,这样把IRP实现串行化。IoStartPacket还可以指定取消例程。一般,队列操作从尾部插入,从首部删除。在StartIo例程结束前,应该调用IoStartNextPacket(从队列中抽取下一个IRP,作为参数调用StartIo例程)。
1 //.cpp
2
3 #include "Driver.h"
4
5
6 #pragma LOCKEDCODE
7 VOID
8 HelloDDKStartIO(
9 IN PDEVICE_OBJECT DeviceObject,
10 IN PIRP Irp
11 )
12 {
13 KIRQL oldirql;
14 KdPrint(("Enter HelloDDKStartIO\n"));
15
16 //获取cancel自旋锁
17 IoAcquireCancelSpinLock(&oldirql);
18 if (Irp!=DeviceObject->CurrentIrp||Irp->Cancel)
19 {
20 //如果当前有正在处理的IRP,则简单的入队列,并直接返回
21 //入队列的工作由系统完成,在StartIO中不用负责
22 IoReleaseCancelSpinLock(oldirql);
23 KdPrint(("Leave HelloDDKStartIO\n"));
24 return;
25 }else
26 {
27 //由于正在处理该IRP,所以不允许调用取消例程
28 //因此将此IRP的取消例程设置为NULL
29 IoSetCancelRoutine(Irp,NULL);
30 IoReleaseCancelSpinLock(oldirql);
31 }
32
33 KEVENT event;
34 KeInitializeEvent(&event,NotificationEvent,FALSE);
35
36 //等3秒
37 LARGE_INTEGER timeout;
38 timeout.QuadPart = -3*1000*1000*10;
39
40 //定义一个3秒的延时,主要是为了模拟该IRP操作需要大概3秒左右时间
41 KeWaitForSingleObject(&event,Executive,KernelMode,FALSE,&timeout);
42
43 Irp->IoStatus.Status = STATUS_SUCCESS;
44 Irp->IoStatus.Information = 0; // no bytes xfered
45 IoCompleteRequest(Irp,IO_NO_INCREMENT);
46
47
48 //在队列中读取一个IRP,并进行StartIo
49 IoStartNextPacket(DeviceObject,TRUE);
50
51 KdPrint(("Leave HelloDDKStartIO\n"));
52 }
53
54 /************************************************************************
55 * 函数名称:DriverEntry
56 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
57 * 参数列表:
58 pDriverObject:从I/O管理器中传进来的驱动对象
59 pRegistryPath:驱动程序在注册表的中的路径
60 * 返回 值:返回初始化驱动状态
61 *************************************************************************/
62 #pragma INITCODE
63 extern "C" NTSTATUS DriverEntry (
64 IN PDRIVER_OBJECT pDriverObject,
65 IN PUNICODE_STRING pRegistryPath )
66 {
67 NTSTATUS status;
68 KdPrint(("Enter DriverEntry\n"));
69
70 //设置卸载函数
71 pDriverObject->DriverUnload = HelloDDKUnload;
72
73 //设置派遣函数
74 pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
75 pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
76 pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
77 pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead;
78 pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
79 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
80 pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
81 pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
82 pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
83
84 //设置StartIO例程
85 pDriverObject->DriverStartIo = HelloDDKStartIO;
86
87 //创建驱动设备对象
88 status = CreateDevice(pDriverObject);
89
90 KdPrint(("Leave DriverEntry\n"));
91 return status;
92 }
93
94 /************************************************************************
95 * 函数名称:CreateDevice
96 * 功能描述:初始化设备对象
97 * 参数列表:
98 pDriverObject:从I/O管理器中传进来的驱动对象
99 * 返回 值:返回初始化状态
100 *************************************************************************/
101 #pragma INITCODE
102 NTSTATUS CreateDevice (
103 IN PDRIVER_OBJECT pDriverObject)
104 {
105 NTSTATUS status;
106 PDEVICE_OBJECT pDevObj;
107 PDEVICE_EXTENSION pDevExt;
108
109 //创建设备名称
110 UNICODE_STRING devName;
111 RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
112
113 //创建设备
114 status = IoCreateDevice( pDriverObject,
115 sizeof(DEVICE_EXTENSION),
116 &(UNICODE_STRING)devName,
117 FILE_DEVICE_UNKNOWN,
118 0, TRUE,
119 &pDevObj );
120 if (!NT_SUCCESS(status))
121 return status;
122
123 pDevObj->Flags |= DO_BUFFERED_IO;
124 pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
125 pDevExt->pDevice = pDevObj;
126 pDevExt->ustrDeviceName = devName;
127
128 //创建符号链接
129 UNICODE_STRING symLinkName;
130 RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
131 pDevExt->ustrSymLinkName = symLinkName;
132 status = IoCreateSymbolicLink( &symLinkName,&devName );
133 if (!NT_SUCCESS(status))
134 {
135 IoDeleteDevice( pDevObj );
136 return status;
137 }
138 return STATUS_SUCCESS;
139 }
140
141 /************************************************************************
142 * 函数名称:HelloDDKUnload
143 * 功能描述:负责驱动程序的卸载操作
144 * 参数列表:
145 pDriverObject:驱动对象
146 * 返回 值:返回状态
147 *************************************************************************/
148 #pragma PAGEDCODE
149 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
150 {
151 PDEVICE_OBJECT pNextObj;
152 KdPrint(("Enter DriverUnload\n"));
153 pNextObj = pDriverObject->DeviceObject;
154 while (pNextObj != NULL)
155 {
156 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
157 pNextObj->DeviceExtension;
158
159 //删除符号链接
160 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
161 IoDeleteSymbolicLink(&pLinkName);
162
163 pNextObj = pNextObj->NextDevice;
164 IoDeleteDevice( pDevExt->pDevice );
165 }
166 }
167
168 /************************************************************************
169 * 函数名称:HelloDDKDispatchRoutin
170 * 功能描述:对读IRP进行处理
171 * 参数列表:
172 pDevObj:功能设备对象
173 pIrp:从IO请求包
174 * 返回 值:返回状态
175 *************************************************************************/
176 #pragma PAGEDCODE
177 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
178 IN PIRP pIrp)
179 {
180 KdPrint(("Enter HelloDDKDispatchRoutin\n"));
181
182 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
183 //建立一个字符串数组与IRP类型对应起来
184 static char* irpname[] =
185 {
186 "IRP_MJ_CREATE",
187 "IRP_MJ_CREATE_NAMED_PIPE",
188 "IRP_MJ_CLOSE",
189 "IRP_MJ_READ",
190 "IRP_MJ_WRITE",
191 "IRP_MJ_QUERY_INFORMATION",
192 "IRP_MJ_SET_INFORMATION",
193 "IRP_MJ_QUERY_EA",
194 "IRP_MJ_SET_EA",
195 "IRP_MJ_FLUSH_BUFFERS",
196 "IRP_MJ_QUERY_VOLUME_INFORMATION",
197 "IRP_MJ_SET_VOLUME_INFORMATION",
198 "IRP_MJ_DIRECTORY_CONTROL",
199 "IRP_MJ_FILE_SYSTEM_CONTROL",
200 "IRP_MJ_DEVICE_CONTROL",
201 "IRP_MJ_INTERNAL_DEVICE_CONTROL",
202 "IRP_MJ_SHUTDOWN",
203 "IRP_MJ_LOCK_CONTROL",
204 "IRP_MJ_CLEANUP",
205 "IRP_MJ_CREATE_MAILSLOT",
206 "IRP_MJ_QUERY_SECURITY",
207 "IRP_MJ_SET_SECURITY",
208 "IRP_MJ_POWER",
209 "IRP_MJ_SYSTEM_CONTROL",
210 "IRP_MJ_DEVICE_CHANGE",
211 "IRP_MJ_QUERY_QUOTA",
212 "IRP_MJ_SET_QUOTA",
213 "IRP_MJ_PNP",
214 };
215
216 UCHAR type = stack->MajorFunction;
217 if (type >= arraysize(irpname))
218 KdPrint((" - Unknown IRP, major type %X\n", type));
219 else
220 KdPrint(("\t%s\n", irpname[type]));
221
222
223 //对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
224 NTSTATUS status = STATUS_SUCCESS;
225 // 完成IRP
226 pIrp->IoStatus.Status = status;
227 pIrp->IoStatus.Information = 0; // bytes xfered
228 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
229
230 KdPrint(("Leave HelloDDKDispatchRoutin\n"));
231
232 return status;
233 }
234
235 VOID
236 OnCancelIRP(
237 IN PDEVICE_OBJECT DeviceObject,
238 IN PIRP Irp
239 )
240 {
241 KdPrint(("Enter CancelReadIRP\n"));
242
243 if (Irp==DeviceObject->CurrentIrp)
244 {
245 //表明当前正在改由StartIo处理
246 //但StartIo并没有获取cancel自旋锁之前
247 //这时候需要
248 KIRQL oldirql = Irp->CancelIrql;
249
250 //释放Cancel自旋锁
251 IoReleaseCancelSpinLock(Irp->CancelIrql);
252
253 IoStartNextPacket(DeviceObject,TRUE);
254
255 KeLowerIrql(oldirql);
256 }else
257 {
258 //从设备队列中将该IRP抽取出来
259 KeRemoveEntryDeviceQueue(&DeviceObject->DeviceQueue,&Irp->Tail.Overlay.DeviceQueueEntry);
260 //释放Cancel自旋锁
261 IoReleaseCancelSpinLock(Irp->CancelIrql);
262 }
263
264
265 //设置完成状态为STATUS_CANCELLED
266 Irp->IoStatus.Status = STATUS_CANCELLED;
267 Irp->IoStatus.Information = 0; // bytes xfered
268 IoCompleteRequest( Irp, IO_NO_INCREMENT );
269
270 KdPrint(("Leave CancelReadIRP\n"));
271 }
272
273
274 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
275 IN PIRP pIrp)
276 {
277 KdPrint(("Enter HelloDDKRead\n"));
278
279 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
280 pDevObj->DeviceExtension;
281
282 //将IRP设置为挂起
283 IoMarkIrpPending(pIrp);
284
285 //将IRP插入系统的队列
286 IoStartPacket(pDevObj,pIrp,0,OnCancelIRP);
287
288 KdPrint(("Leave HelloDDKRead\n"));
289
290 //返回pending状态
291 return STATUS_PENDING;
292 }
293
294 //应用程序
295 #include <windows.h>
296 #include <stdio.h>
297 #include <process.h>
298
299 UINT WINAPI Thread(LPVOID context)
300 {
301 printf("Enter Thread\n");
302 //等待5秒
303 OVERLAPPED overlap={0};
304 overlap.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
305 UCHAR buffer[10];
306 ULONG ulRead;
307
308 BOOL bRead = ReadFile(*(PHANDLE)context,buffer,10,&ulRead,&overlap);
309
310 //可以试验取消例程
311 //CancelIo(*(PHANDLE)context);
312 WaitForSingleObject(overlap.hEvent,INFINITE);
313 return 0;
314 }
315
316 int main()
317 {
318 HANDLE hDevice =
319 CreateFile("\\\\.\\HelloDDK",
320 GENERIC_READ | GENERIC_WRITE,
321 FILE_SHARE_READ,
322 NULL,
323 OPEN_EXISTING,
324 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//此处设置FILE_FLAG_OVERLAPPED
325 NULL );
326
327 if (hDevice == INVALID_HANDLE_VALUE)
328 {
329 printf("Open Device failed!");
330 return 1;
331 }
332
333 HANDLE hThread[2];
334 hThread[0] = (HANDLE) _beginthreadex (NULL,0,Thread,&hDevice,0,NULL);
335 hThread[1] = (HANDLE) _beginthreadex (NULL,0,Thread,&hDevice,0,NULL);
336
337 //主线程等待两个子线程结束
338 WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
339
340 //创建IRP_MJ_CLEANUP IRP
341 CloseHandle(hDevice);
342
343 return 0;
344 }
示例代码 P267
使用StartIo时,需要IRP的派遣函数返回挂起状态。
2)自定义StartIo
系统提供的StartIo只能使用一个队列,如果想把读,写等操作分开进行串行化,那就要多(2)个队列。需要自定义。我们用DDK提供的 PKDEVICE_QUEUE存储队列,队列中每个元素用PKDEVICE_QUEUE_ENTRY表示。自定义StartIo里,需要我们自已维护“入队”“出队”操作。
初始化队列:KeInitializeDeviceQueue
插入:KeInsertDeviceQueue
删除:KeRemoveDeviceQueue
1 //.h
2 #pragma once
3
4 #ifdef __cplusplus
5 extern "C"
6 {
7 #endif
8 #include <NTDDK.h>
9 #ifdef __cplusplus
10 }
11 #endif
12
13 #define PAGEDCODE code_seg("PAGE")
14 #define LOCKEDCODE code_seg()
15 #define INITCODE code_seg("INIT")
16
17 #define PAGEDDATA data_seg("PAGE")
18 #define LOCKEDDATA data_seg()
19 #define INITDATA data_seg("INIT")
20
21 #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
22
23 typedef struct _DEVICE_EXTENSION {
24 PDEVICE_OBJECT pDevice;
25 UNICODE_STRING ustrDeviceName; //设备名称
26 UNICODE_STRING ustrSymLinkName; //符号链接名
27 KDEVICE_QUEUE device_queue; //设备队列
28 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
29
30 // 函数声明
31
32 NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject);
33 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject);
34 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
35 IN PIRP pIrp);
36 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
37 IN PIRP pIrp);
38 NTSTATUS HelloDDKCleanUp(IN PDEVICE_OBJECT pDevObj,
39 IN PIRP pIrp);
40 //.cpp
41 #include "Driver.h"
42
43
44 #pragma LOCKEDCODE
45 VOID
46 MyStartIo(
47 IN PDEVICE_OBJECT DeviceObject,
48 IN PIRP pFistIrp
49 )
50 {
51 KdPrint(("Enter MyStartIo\n"));
52
53 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
54 DeviceObject->DeviceExtension;
55
56 PKDEVICE_QUEUE_ENTRY device_entry;
57
58 PIRP Irp = pFistIrp;
59 do
60 {
61 KEVENT event;
62 KeInitializeEvent(&event,NotificationEvent,FALSE);
63
64 //等3秒
65 LARGE_INTEGER timeout;
66 timeout.QuadPart = -3*1000*1000*10;
67
68 //定义一个3秒的延时,主要是为了模拟该IRP操作需要大概3秒左右时间
69 KeWaitForSingleObject(&event,Executive,KernelMode,FALSE,&timeout);
70
71 KdPrint(("Complete a irp:%x\n",Irp));
72 Irp->IoStatus.Status = STATUS_SUCCESS;
73 Irp->IoStatus.Information = 0; // no bytes xfered
74 IoCompleteRequest(Irp,IO_NO_INCREMENT);
75
76 device_entry=KeRemoveDeviceQueue(&pDevExt->device_queue);
77 KdPrint(("device_entry:%x\n",device_entry));
78 if (device_entry==NULL)
79 {
80 break;
81 }
82
83 Irp = CONTAINING_RECORD(device_entry, IRP, Tail.Overlay.DeviceQueueEntry);
84 }while(1);
85
86 KdPrint(("Leave MyStartIo\n"));
87 }
88
89 /************************************************************************
90 * 函数名称:DriverEntry
91 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
92 * 参数列表:
93 pDriverObject:从I/O管理器中传进来的驱动对象
94 pRegistryPath:驱动程序在注册表的中的路径
95 * 返回 值:返回初始化驱动状态
96 *************************************************************************/
97 #pragma INITCODE
98 extern "C" NTSTATUS DriverEntry (
99 IN PDRIVER_OBJECT pDriverObject,
100 IN PUNICODE_STRING pRegistryPath )
101 {
102 NTSTATUS status;
103 KdPrint(("Enter DriverEntry\n"));
104
105 //设置卸载函数
106 pDriverObject->DriverUnload = HelloDDKUnload;
107
108 //设置派遣函数
109 pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
110 pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
111 pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
112 pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead;
113 pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
114 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
115 pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
116 pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
117 pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
118
119 //创建驱动设备对象
120 status = CreateDevice(pDriverObject);
121
122 KdPrint(("Leave DriverEntry\n"));
123 return status;
124 }
125
126 /************************************************************************
127 * 函数名称:CreateDevice
128 * 功能描述:初始化设备对象
129 * 参数列表:
130 pDriverObject:从I/O管理器中传进来的驱动对象
131 * 返回 值:返回初始化状态
132 *************************************************************************/
133 #pragma INITCODE
134 NTSTATUS CreateDevice (
135 IN PDRIVER_OBJECT pDriverObject)
136 {
137 NTSTATUS status;
138 PDEVICE_OBJECT pDevObj;
139 PDEVICE_EXTENSION pDevExt;
140
141 //创建设备名称
142 UNICODE_STRING devName;
143 RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
144
145 //创建设备
146 status = IoCreateDevice( pDriverObject,
147 sizeof(DEVICE_EXTENSION),
148 &(UNICODE_STRING)devName,
149 FILE_DEVICE_UNKNOWN,
150 0, TRUE,
151 &pDevObj );
152 if (!NT_SUCCESS(status))
153 return status;
154
155 pDevObj->Flags |= DO_BUFFERED_IO;
156 pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
157 pDevExt->pDevice = pDevObj;
158 pDevExt->ustrDeviceName = devName;
159
160 RtlZeroBytes(&pDevExt->device_queue,sizeof(pDevExt->device_queue));
161 KeInitializeDeviceQueue(&pDevExt->device_queue);
162
163 //创建符号链接
164 UNICODE_STRING symLinkName;
165 RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
166 pDevExt->ustrSymLinkName = symLinkName;
167 status = IoCreateSymbolicLink( &symLinkName,&devName );
168 if (!NT_SUCCESS(status))
169 {
170 IoDeleteDevice( pDevObj );
171 return status;
172 }
173 return STATUS_SUCCESS;
174 }
175
176 /************************************************************************
177 * 函数名称:HelloDDKUnload
178 * 功能描述:负责驱动程序的卸载操作
179 * 参数列表:
180 pDriverObject:驱动对象
181 * 返回 值:返回状态
182 *************************************************************************/
183 #pragma PAGEDCODE
184 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
185 {
186 PDEVICE_OBJECT pNextObj;
187 KdPrint(("Enter DriverUnload\n"));
188 pNextObj = pDriverObject->DeviceObject;
189 while (pNextObj != NULL)
190 {
191 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
192 pNextObj->DeviceExtension;
193
194 //删除符号链接
195 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
196 IoDeleteSymbolicLink(&pLinkName);
197
198 pNextObj = pNextObj->NextDevice;
199 IoDeleteDevice( pDevExt->pDevice );
200 }
201 }
202
203 /************************************************************************
204 * 函数名称:HelloDDKDispatchRoutin
205 * 功能描述:对读IRP进行处理
206 * 参数列表:
207 pDevObj:功能设备对象
208 pIrp:从IO请求包
209 * 返回 值:返回状态
210 *************************************************************************/
211 #pragma PAGEDCODE
212 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
213 IN PIRP pIrp)
214 {
215 KdPrint(("Enter HelloDDKDispatchRoutin\n"));
216
217 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
218 //建立一个字符串数组与IRP类型对应起来
219 static char* irpname[] =
220 {
221 "IRP_MJ_CREATE",
222 "IRP_MJ_CREATE_NAMED_PIPE",
223 "IRP_MJ_CLOSE",
224 "IRP_MJ_READ",
225 "IRP_MJ_WRITE",
226 "IRP_MJ_QUERY_INFORMATION",
227 "IRP_MJ_SET_INFORMATION",
228 "IRP_MJ_QUERY_EA",
229 "IRP_MJ_SET_EA",
230 "IRP_MJ_FLUSH_BUFFERS",
231 "IRP_MJ_QUERY_VOLUME_INFORMATION",
232 "IRP_MJ_SET_VOLUME_INFORMATION",
233 "IRP_MJ_DIRECTORY_CONTROL",
234 "IRP_MJ_FILE_SYSTEM_CONTROL",
235 "IRP_MJ_DEVICE_CONTROL",
236 "IRP_MJ_INTERNAL_DEVICE_CONTROL",
237 "IRP_MJ_SHUTDOWN",
238 "IRP_MJ_LOCK_CONTROL",
239 "IRP_MJ_CLEANUP",
240 "IRP_MJ_CREATE_MAILSLOT",
241 "IRP_MJ_QUERY_SECURITY",
242 "IRP_MJ_SET_SECURITY",
243 "IRP_MJ_POWER",
244 "IRP_MJ_SYSTEM_CONTROL",
245 "IRP_MJ_DEVICE_CHANGE",
246 "IRP_MJ_QUERY_QUOTA",
247 "IRP_MJ_SET_QUOTA",
248 "IRP_MJ_PNP",
249 };
250
251 UCHAR type = stack->MajorFunction;
252 if (type >= arraysize(irpname))
253 KdPrint((" - Unknown IRP, major type %X\n", type));
254 else
255 KdPrint(("\t%s\n", irpname[type]));
256
257 //对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
258 NTSTATUS status = STATUS_SUCCESS;
259 // 完成IRP
260 pIrp->IoStatus.Status = status;
261 pIrp->IoStatus.Information = 0; // bytes xfered
262 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
263
264 KdPrint(("Leave HelloDDKDispatchRoutin\n"));
265
266 return status;
267 }
268
269 VOID
270 OnCancelIRP(
271 IN PDEVICE_OBJECT DeviceObject,
272 IN PIRP Irp
273 )
274 {
275 KdPrint(("Enter CancelReadIRP\n"));
276
277 //释放Cancel自旋锁
278 IoReleaseCancelSpinLock(Irp->CancelIrql);
279
280 //设置完成状态为STATUS_CANCELLED
281 Irp->IoStatus.Status = STATUS_CANCELLED;
282 Irp->IoStatus.Information = 0; // bytes xfered
283 IoCompleteRequest( Irp, IO_NO_INCREMENT );
284
285 KdPrint(("Leave CancelReadIRP\n"));
286 }
287
288 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
289 IN PIRP pIrp)
290 {
291 KdPrint(("Enter HelloDDKRead\n"));
292
293 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
294 pDevObj->DeviceExtension;
295
296 //将IRP设置为挂起
297 IoMarkIrpPending(pIrp);
298
299 IoSetCancelRoutine(pIrp,OnCancelIRP);
300
301 KIRQL oldirql;
302 //提升IRP至DISPATCH_LEVEL
303 KeRaiseIrql(DISPATCH_LEVEL, &oldirql);
304
305 KdPrint(("HelloDDKRead irp :%x\n",pIrp));
306
307 KdPrint(("DeviceQueueEntry:%x\n",&pIrp->Tail.Overlay.DeviceQueueEntry));
308 if (!KeInsertDeviceQueue(&pDevExt->device_queue, &pIrp->Tail.Overlay.DeviceQueueEntry))
309 MyStartIo(pDevObj,pIrp);
310
311 //将IRP降至原来IRQL
312 KeLowerIrql(oldirql);
313
314 KdPrint(("Leave HelloDDKRead\n"));
315
316 //返回pending状态
317 return STATUS_PENDING;
318 }
319
320 //应用程序
321 #include <windows.h>
322 #include <stdio.h>
323 #include <process.h>
324
325 UINT WINAPI Thread(LPVOID context)
326 {
327 printf("Enter Thread\n");
328 OVERLAPPED overlap={0};
329 overlap.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
330 UCHAR buffer[10];
331 ULONG ulRead;
332
333 BOOL bRead = ReadFile(*(PHANDLE)context,buffer,10,&ulRead,&overlap);
334
335 WaitForSingleObject(overlap.hEvent,INFINITE);
336 return 0;
337 }
338
339 int main()
340 {
341 HANDLE hDevice =
342 CreateFile("\\\\.\\HelloDDK",
343 GENERIC_READ | GENERIC_WRITE,
344 FILE_SHARE_READ,
345 NULL,
346 OPEN_EXISTING,
347 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//此处设置FILE_FLAG_OVERLAPPED
348 NULL );
349
350 if (hDevice == INVALID_HANDLE_VALUE)
351 {
352 printf("Open Device failed!");
353 return 1;
354 }
355
356 HANDLE hThread[2];
357 hThread[0] = (HANDLE) _beginthreadex (NULL,0,Thread,&hDevice,0,NULL);
358 hThread[1] = (HANDLE) _beginthreadex (NULL,0,Thread,&hDevice,0,NULL);
359
360 //主线程等待两个子线程结束
361 WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
362
363 //创建IRP_MJ_CLEANUP IRP
364 CloseHandle(hDevice);
365
366 return 0;
367 }
示例代码 P272
4、中断服务例程(ISR)和DPC例程
DDK 提供内核函数IoConnectInterrupt把中断对象与ISR联系起来。ISR运行在DIRQL级别,高于普通线程的优先级。派遣函数,StartIo例程随时会被中断服务程序所打断,为了不让ISR打断,可以将IRQL升到相应的DIRQL。DDK提供了与ISR函数同步的内核函数
KeSynchronizeExecution。当运行到KeSynchronizeExecution时,ISR不会打断KeSynchronizeExecution提供的同步函数,我们可将同步代码放到KeSynchronizeExecution提供的同步函数中。
DPC(deferred procedure call )例程
ISR处于较高的IRQL,会打断正常运行的线程。DPC处于DISPATCH_LEVEL。所以,一般,ISR中的代码应该尽量少,不太重要的代码放入DPC中。
KeInitializeDpc