说明:
(1)当IRP被IoCompleteRequest完成时,就开始从设备堆栈一层一层的向上“回卷”。
(2)当在某一层堆栈遇到有完成例程,则会进入到该完成例程,若这个完成例程返回STATUS_MORE_PROCESSING_REQUIRED,则停止向上“回卷”。
(3)此时本层设备栈又重新获得对IRP的控制权,并且该IRP又变成未完成状态,需要再次调用IoCompleteRequest来完成IRP。
下面示例代码:
///
///
/// Copyright (c) 2014 - <company name here>
///
/// Original filename: DriverB.cpp
/// Project : DriverB
/// Date of creation : 2014-06-27
/// Author(s) : <author name(s)>
///
/// Purpose : <description>
///
/// Revisions:
/// 0000 [2014-06-27] Initial revision.
///
///
// $Id$
#ifdef __cplusplus
extern "C" {
#endif
#include <ntddk.h>
#include <string.h>
#ifdef __cplusplus
}; // extern "C"
#endif
#include "DriverB.h"
#ifdef __cplusplus
namespace { // anonymous namespace to limit the scope of this global variable!
#endif
PDRIVER_OBJECT pdoGlobalDrvObj = 0;
#ifdef __cplusplus
}; // anonymous namespace
#endif
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT pCreateDevObj;
UNICODE_STRING usCreateDevName;
UNICODE_STRING usCreateLinkName;
PDEVICE_OBJECT pTargetedDevObj;
}DEVICE_EXTENSION,*PDEVICE_EXTENSION;
NTSTATUS DRIVERB_DispatchCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
// Irp->IoStatus.Status = status;
// Irp->IoStatus.Information = 0;
// IoCompleteRequest(Irp, IO_NO_INCREMENT);
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(pdx->pTargetedDevObj,Irp);
return status;
}
NTSTATUS DRIVERB_DispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
switch(irpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_DRIVERB_OPERATION:
// status = SomeHandlerFunction(irpSp);
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
break;
}
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
VOID DRIVERB_DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
PDEVICE_OBJECT pdoNextDeviceObj = pdoGlobalDrvObj->DeviceObject;
//IoDeleteSymbolicLink(&usSymlinkName);
// Delete all the device objects
while(pdoNextDeviceObj)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pdoNextDeviceObj->DeviceExtension;
pdoNextDeviceObj = pDevExt->pCreateDevObj->NextDevice;//pdoThisDeviceObj->NextDevice;
IoDetachDevice(pDevExt->pTargetedDevObj);
IoDeleteSymbolicLink(&pDevExt->usCreateLinkName);
IoDeleteDevice(pDevExt->pCreateDevObj);
}
}
NTSTATUS
IoReadCompletion(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp,
__in PVOID Context
)
{
//进入此函数标志底层驱动设备将IRP完成
KdPrint(("entry..IoReadCompletion..."));
/*
if (Irp->PendingReturned)
{
//传播pending位
IoMarkIrpPending(Irp);//完成例程返回STATUS_MORE_PROCESSING_REQUIRED时,不可以设置IoMarkIrpPending
//PKEVENT PKevent = (PKEVENT)Context;
//KeSetEvent(PKevent,IO_NO_INCREMENT,FALSE);
}
*/
KdPrint(("leave..IoReadCompletion..."));
PKEVENT PKevent = (PKEVENT)Context;
KeSetEvent(PKevent,IO_NO_INCREMENT,FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;//STATUS_SUCCESS;
}
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
KdPrint(("entry..DispatchRead..."));
//将irp下发给 下层驱动处理
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
//将当前IO堆栈拷贝到下一层堆栈
IoCopyCurrentIrpStackLocationToNext(pIrp);
//设置KEVENT传递给完成例程,并将完成例程返回STATUS_MORE_PROCESSING_REQUIRED,irp“回卷”时重新获得IRP的控制权
KEVENT kEvent;
KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
//设置IRP的完成例程
IoSetCompletionRoutine(pIrp,IoReadCompletion,&kEvent,TRUE,TRUE,TRUE);
status = IoCallDriver(pDevExt->pTargetedDevObj,pIrp);//转发IRP给下层驱动
if (status == STATUS_PENDING)
{
KdPrint(("DrvierB:DispatchRead::IoCallDriver STATUS_PENDING...."));
KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
KdPrint(("DrvierB:IoReadCompletion::finish STATUS_PENDING...."));
status = pIrp->IoStatus.Status;
}
//此时需要再次调用来完成IRP,但是本程序再此处会有发送多个IRP完成的蓝屏?????为什么?
//原因://完成例程返回STATUS_MORE_PROCESSING_REQUIRED时,不可以设置IoMarkIrpPending
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
KdPrint(("leave..DispatchRead..."));
return status;
}
#ifdef __cplusplus
extern "C" {
#endif
NTSTATUS DriverEntry(
IN OUT PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
PDEVICE_OBJECT pdoDeviceObj = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
pdoGlobalDrvObj = DriverObject;
PDEVICE_EXTENSION pDevExt = NULL;
KdPrint(("entry..DriverB::::DriverEntry..."));
// Create the device object.
if(!NT_SUCCESS(status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),//0,
&usDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&pdoDeviceObj
)))
{
KdPrint(("IoCreateDevice Error status:0x%x",status));
// Bail out (implicitly forces the driver to unload).
return status;
};
// Now create the respective symbolic link object
if(!NT_SUCCESS(status = IoCreateSymbolicLink(
&usSymlinkName,
&usDeviceName
)))
{
KdPrint(("IoCreateSymbolicLink Error status:0x%x",status));
IoDeleteDevice(pdoDeviceObj);
return status;
}
// NOTE: You need not provide your own implementation for any major function that
// you do not want to handle. I have seen code using DDKWizard that left the
// *empty* dispatch routines intact. This is not necessary at all!
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DRIVERB_DispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DRIVERB_DispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->DriverUnload = DRIVERB_DriverUnload;
//\\Device\\MDeviceA
UNICODE_STRING usAttDevName;
RtlInitUnicodeString(&usAttDevName,L"\\Device\\MDeviceA");
PDEVICE_OBJECT pAttDevObj;
PFILE_OBJECT pAttFileObj;
status = IoGetDeviceObjectPointer(&usAttDevName,FILE_ALL_ACCESS,&pAttFileObj,&pAttDevObj);
if (!NT_SUCCESS(status))
{
KdPrint(("IoGetDeviceObjectPointer Error status:0x%x",status));
IoDeleteSymbolicLink(&usSymlinkName);
IoDeleteDevice(pdoDeviceObj);
return status;
}
PDEVICE_OBJECT PAttachedDevice = IoAttachDeviceToDeviceStack(pdoDeviceObj,pAttDevObj);
if (PAttachedDevice == NULL)
{
KdPrint(("IoAttachDeviceToDeviceStack Error status:0x%x",status));
ObDereferenceObject(pAttFileObj);
IoDeleteSymbolicLink(&usSymlinkName);
IoDeleteDevice(pdoDeviceObj);
}
//初始化设备扩展
pDevExt = (PDEVICE_EXTENSION)pdoDeviceObj->DeviceExtension;
pDevExt->usCreateDevName = usDeviceName;
pDevExt->usCreateLinkName = usSymlinkName;
pDevExt->pCreateDevObj = pdoDeviceObj;
pDevExt->pTargetedDevObj = PAttachedDevice;
//设置设备属性匹配被绑定的设备
pdoDeviceObj->Characteristics = PAttachedDevice->Characteristics;
pdoDeviceObj->DeviceType = PAttachedDevice->DeviceType;
pdoDeviceObj->Flags &= ~ DO_DEVICE_INITIALIZING;
pdoDeviceObj->Flags |= PAttachedDevice->Flags &(DO_BUFFERED_IO | DO_DIRECT_IO);
ObDereferenceObject(&pAttFileObj);
KdPrint(("leave..DriverB::::DriverEntry..."));
status = STATUS_SUCCESS;
return status/*STATUS_SUCCESS*/;
}
#ifdef __cplusplus
}; // extern "C"
#endif