在将Irp发送给底层驱动程序, 或者其他驱动之前, 我们可以对Irp设置一个完成例程, 这样一旦在底层驱动程序将Irp完成以后, Irp完成例程将被触发, 通过设置完成例程可以方便的使程序员了解其他驱动对Irp进行的处理.

完成例程是一种很暴力的东西, 非常有用, 必须要熟练掌握, 当调用IoCallDriver将Irp的控制权交给被动驱动程序的时候有两种情况, 一种是调用的设备同步完成了这个Irp, 那么这时候从IoCallDriver返回的时候Irp已经被完成了, 另外一种的话, 就是调用的时候是异步操作. IoCallDriver会立刻返回IoCallDriver, 但此时并没有真正的完成Irp.在这种情况下, 调用IoCallDriver前, 先对Irp注册一个完成例程, 当底层驱动或者其他驱动完成的此Irp时, 此完成例程立刻被调用.

这就是空手套白狼啊, 过滤的暴力之处, 要设置完成例程只需要在当前的Io堆栈(Io_Stack_Location)中的CompletionRoutine子域. 如果这个字段非空, 那么在Irp完成的时候会回卷看到这个字段非空就会调用我们设置的完成例程. 当然微软已经提供了宏方便我们设置这个区域, IoSetCompletionRoutine. 就是它..

还有一点, 虽然我们没有动Irp但是这里不能够直接跳过当前的堆栈, 必须调用IoCopyCurrentIrpStackToNext函数, 将本层的I/O堆栈Copy到下一层的I/O堆栈. 这样在Irp完成的时候就会进入我们设置的完成例程, 这时候我们的完成例程处理完后可以返回两个值, 一个是Status_Success(Status_Continue_Completion)两个是等价的, 如果返回这个值, 那么故事就在这里就结束了, Irp改回卷回卷, 改干嘛干嘛. 但是如果返回Status_Continue_Completion, 那么我们的分发函数就又会获得控制权, 多暴力啊.

还有一个问题就是传播Pending位了, 这个东西的话我们设置了完成例程必须我们帮忙传播这个位了.但是是不可以在IoCallDriver后去动Irp的, 记住这点在调用IoCallDriver以后Irp就不属于驱动这一层了. 所以这个事情的话只能留给完成例程来做了. 所以记得在完成里面里面调用IoMarkIrpPending就好了..

这边是代码, 一个测试驱动和前面一样, 还有一个用户态这边的程序, 就是打开设备一个写设备, 一个读设备和前面也一样就不贴了:

```c++ {tabWidth=8} /* Windows 内核下驱动程序调用驱动程序设置了完成例程 测试驱动 编译方法参见makefile. TAB = 8 */ #include

#define DEVICE_NAME L”\\Device\\DevCompletionRoutine” #define SYSLINK_NAME L”\\??\\SysLinkCompletionRoutine” #define TARGET_DEVICE_NAME L”\\Device\\DevTestDriver”

typedef struct tagDevice_Ext { PDEVICE_OBJECT pDeviceObj; PDEVICE_OBJECT pLowDevice; UNICODE_STRING USzDeviceName; UNICODE_STRING USzSysLinkName; } DEVICE_EXT, *PDEVICE_EXT;

//=========================================================================== //驱动卸载例程 //=========================================================================== VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) { PDEVICE_EXT pDeviceExt = NULL; PDEVICE_OBJECT pNextDeviceObj = NULL;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
pNextDeviceObj = pDriverObj->DeviceObject;

while ( pNextDeviceObj  ) {
    pDeviceExt = pNextDeviceObj->DeviceExtension;

    IoDetachDevice( pDeviceExt->pLowDevice );

    IoDeleteDevice( pDeviceExt->pDeviceObj );

    IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName );

    KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) );

    pNextDeviceObj = pNextDeviceObj->NextDevice;
}

} //=========================================================================== //所有不关心的Irp处理 //=========================================================================== NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
pDeviceExt = pDeviceObj->DeviceExtension;

//跳过当前堆栈
IoSkipCurrentIrpStackLocation( pIrp );

//调用下层驱动
Status = IoCallDriver( pDeviceExt->pLowDevice, pIrp );

KdPrint( ( "不关心的Irp来了一次!\n" ) );
return Status;

}

//=========================================================================== //读取请求的完成例程 //=========================================================================== NTSTATUS CompletionRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp, PVOID pContext ) { ULONG ulReadLen; PIO_STACK_LOCATION pStack = NULL; PDEVICE_EXT pDeviceExt = NULL;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
_asm int 3;
pStack = IoGetCurrentIrpStackLocation( pIrp );

pDeviceExt = pDeviceObj->DeviceExtension;
ulReadLen = pStack->Parameters.Read.Length;

//再次将数据改写
RtlFillMemory( pIrp->AssociatedIrp.SystemBuffer, ulReadLen, 'c' );

//进入此函数标志底层驱动设备将IRP完成
KdPrint( ( "Completion:读取请求的完成例程\n" ) );
if ( pIrp->PendingReturned ) {
    //传播pending位
    IoMarkIrpPending( pIrp );
}

//如果想分发函数继续获得控制器那么返回
//STATUS_MORE_PROCESSING_REQUIRED
return STATUS_CONTINUE_COMPLETION;

} //=========================================================================== //读取请求处理例程 //=========================================================================== NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
_asm int 3;
pDeviceExt = pDeviceObj->DeviceExtension;

//将当前IRP堆栈拷贝底层堆栈
IoCopyCurrentIrpStackLocationToNext( pIrp );

//设置完成例程
IoSetCompletionRoutine( pIrp, &CompletionRead, NULL, TRUE, TRUE, TRUE );

//调用底层驱动程序(只要调用了函数就不能够去操作Irp
Status = IoCallDriver( pDeviceExt->pLowDevice, pIrp );

if ( Status == STATUS_PENDING ) {
    KdPrint( ( "Completion: DispatchRead->Irp被挂起!\n" ) );
}

KdPrint( ( "Completion:DispatchRead来了一次\n" ) );
return Status;

} //=========================================================================== //写入请求处理例程 //=========================================================================== NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { ULONG uWriteLen; NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL; PIO_STACK_LOCATION pStack = NULL;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
pStack = IoGetCurrentIrpStackLocation( pIrp );

uWriteLen = pStack->Parameters.Write.Length;
pDeviceExt = pDeviceObj->DeviceExtension;

//将用户层写入的数据修改掉
RtlFillMemory( pIrp->AssociatedIrp.SystemBuffer, uWriteLen, 'b' );

//跳过当前堆栈
IoSkipCurrentIrpStackLocation( pIrp );

Status = IoCallDriver( pDeviceExt->pLowDevice, pIrp );
return Status;

} //=========================================================================== //驱动程序入口 //=========================================================================== NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) { NTSTATUS Status; ULONG i; PDEVICE_EXT pDeviceExt = NULL; PFILE_OBJECT pTargetFileObj = NULL; PDEVICE_OBJECT pTargetDevice = NULL; PDEVICE_OBJECT pLowDevice = NULL;
PDEVICE_OBJECT pDeviceObj = NULL; UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME ); UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYSLINK_NAME ); UNICODE_STRING USzTargetDeviceName = RTL_CONSTANT_STRING( TARGET_DEVICE_NAME );

1
2
3
4
5
6
for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
    pDriverObj->MajorFunction\[i\] = &DispatchRoutine;
}
pDriverObj->MajorFunction\[IRP_MJ_WRITE\] = &DispatchWrite;
pDriverObj->MajorFunction\[IRP_MJ_READ\] = &DispatchRead;
pDriverObj->DriverUnload = &DriverUnLoad;

//————————————————————————— do { _asm int 3; Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObj ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( “创建设备失败!\n” ) ); break; }

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    Status = IoCreateSymbolicLink( &USzSysLinkName, &USzDeviceName );
    if ( !NT_SUCCESS( Status ) ) {
        KdPrint( ( "创建符号链接失败!\n" ) );
        break;
    }

    //获取目标设备的设备对象
    Status = IoGetDeviceObjectPointer( &USzTargetDeviceName, FILE_ALL_ACCESS,
                       &pTargetFileObj, &pTargetDevice );
    if ( !NT_SUCCESS( Status ) ) {
        KdPrint( ( "获取目标设备失败!\n" ) );
        break;
    }

    //将自己的设备对象挂载在目标设备对象上
    pLowDevice = IoAttachDeviceToDeviceStack( pDeviceObj, pTargetDevice );
    if ( !pLowDevice ) {
        KdPrint( ( "设备挂载失败!\n" ) );
        Status = STATUS_UNSUCCESSFUL;
        break;
    }

    //设置设备类型, 属性
    pDeviceObj->DeviceType = pLowDevice->DeviceType;
    pDeviceObj->Characteristics = pLowDevice->DeviceType;
    //启动设备
    pDeviceObj->Flags &= ~DO_DEVICE_INITIALIZING;
    //设置缓冲区操作方式
    pDeviceObj->Flags |= pLowDevice->Flags & ( DO_BUFFERED_IO | DO_DIRECT_IO );
    //设置设备扩展
    pDeviceExt = pDeviceObj->DeviceExtension;
    pDeviceExt->pDeviceObj = pDeviceObj;
    pDeviceExt->pLowDevice = pLowDevice;
    pDeviceExt->USzDeviceName = USzDeviceName;
    pDeviceExt->USzSysLinkName = USzSysLinkName;

    if ( pTargetFileObj ) {
        ObDereferenceObject( pTargetFileObj );
        pTargetFileObj = NULL;
    }
    KdPrint( ( "设备绑定成功!\n" ) );

} while ( FALSE );

//————————————————————————— if ( !NT_SUCCESS( Status ) ) { if ( pDeviceObj ) { IoDeleteSymbolicLink( &USzSysLinkName ); IoDeleteDevice( pDeviceObj ); }

1
2
3
4
5
6
    //这边要卸载的是文件对象
    if ( pTargetFileObj ) {
        ObDereferenceObject( pTargetFileObj );
    }
}
return Status;

}