IRP调用IoSkipCurrentIrpStackLocation与IoCopyCurrentIrpStackLocationToNext的区别
2022-08-01
146
20
当IPR需要传递给下层设备时,一般的操作有两种。
第一种是直接下传:
IoCopyCurrentIrpStackLocationToNext(irp);
status = IoCallDriver(parentFdoExt->fdo, irp);
这种情况下是保留当前驱动栈对该IRP的IO_STACK_LOCATION,这是因为:
FORCEINLINE
VOID
IoCopyCurrentIrpStackLocationToNext(
_Inout_ PIRP Irp
)
/*--
Routine Description:
This routine is invoked to copy the IRP stack arguments and file
pointer from the current IrpStackLocation to the next
in an I/O Request Packet (IRP).
If the caller wants to call IoCallDriver with a completion routine
but does not wish to change the arguments otherwise,
the caller first calls IoCopyCurrentIrpStackLocationToNext,
then IoSetCompletionRoutine, then IoCallDriver.
Arguments:
Irp - Pointer to the I/O Request Packet.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION irpSp;
PIO_STACK_LOCATION nextIrpSp;
irpSp = IoGetCurrentIrpStackLocation(Irp);
nextIrpSp = IoGetNextIrpStackLocation(Irp);
RtlCopyMemory( nextIrpSp, irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
nextIrpSp->Control = 0;
}
可以以看到IoCopyCurrentIrpStackLocationToNext只是将当前的栈信息复制到下一层中(不包括完成例程)
而第二种是:
IoSkipCurrentIrpStackLocation(irp);
status = IoCallDriver(parentFdoExt->topDevObj, irp);
跳过当前栈,让下层驱动使用当前的驱动栈。所以使用IoSkipCurrentIrpStackLocation函数先使IRP的IO_STACK_LOCATION上移,上移Irp->Tail.Overlay.CurrentStackLocation指针的上移和当前位置层位置CurrentLocation的上移:
ORCEINLINE
VOID
IoSkipCurrentIrpStackLocation (
_Inout_ PIRP Irp
)
/*--
Routine Description:
This routine is invoked to increment the current stack location of
a given IRP.
If the caller wishes to call the next driver in a stack, and does not
wish to change the arguments, nor does he wish to set a completion
routine, then the caller first calls IoSkipCurrentIrpStackLocation
and the calls IoCallDriver.
Arguments:
Irp - Pointer to the I/O Request Packet.
Return Value:
None
--*/
{
NT_ASSERT(Irp->CurrentLocation <= Irp->StackCount);
Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;
}
最终它们都是调用的是IoCalldriver函数:http://www.pnpon.com/article/detail-361.html
从源代码可以看到:
其仅是检查当前位直CurrentLocation。然后获取下一层的IO_STACK_LOCATION并赋于Irp->Tail.Overlay.CurrentStackLocation,然后执行DeviceObject对应的DriverObject对应的函数。
其实从这里也可以看出,IoCallDriver这个函数的调用是需要一些准备工作的,而且比较重要。这些准备工作是根据用户的需求而设置不同。所以IoCallDriver函数有点像半个函数。