首页
社区
课程
招聘
[求助]IoSetCompletionRoutine
发表于: 2010-1-19 23:57 7375

[求助]IoSetCompletionRoutine

2010-1-19 23:57
7375
VOID
IoSetCompletionRoutine(
    __in PIRP Irp,
    __in_opt PIO_COMPLETION_ROUTINE CompletionRoutine,
    __in_opt __drv_aliasesMem PVOID Context,
    __in BOOLEAN InvokeOnSuccess,
    __in BOOLEAN InvokeOnError,
    __in BOOLEAN InvokeOnCancel
    )
{
    PIO_STACK_LOCATION irpSp;
    ASSERT( (InvokeOnSuccess || InvokeOnError || InvokeOnCancel) ? (CompletionRoutine != NULL) : TRUE );
    irpSp = IoGetNextIrpStackLocation(Irp);
    irpSp->CompletionRoutine = CompletionRoutine;
    irpSp->Context = Context;
    irpSp->Control = 0;

    if (InvokeOnSuccess) {
        irpSp->Control = SL_INVOKE_ON_SUCCESS;
    }

    if (InvokeOnError) {
        irpSp->Control |= SL_INVOKE_ON_ERROR;
    }

    if (InvokeOnCancel) {
        irpSp->Control |= SL_INVOKE_ON_CANCEL;
    }
}

奇怪,IoSetCompletionRoutine设置的完成例程居然被放在了下一层的io_stack_location中,额,它为啥要放在下一层,而不是本层呢,明明是完成本层未了之事

[课程]Android-CTF解题方法汇总!

收藏
免费 0
支持
分享
最新回复 (12)
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
下面是我的理解。
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,MyCompletionRoutine,NULL,TRUE,TRUE,TRUE);
//上面二句把本层的IRP复制到下一层,然后在下一层设完成例程。
return IoCallDriver(pDeviceMy->pTargetDeviceObject, pIrp);
//调用IoCallDriver把IRP传到下一层中。这时cpu执行下一层的IRP分发,在下一层IRP分发调用IoCompleteRequest后,表示IRP结束,会一层层出栈,这时,当结束后会检查本层的设有完成例程,所以立刻进入设置好的完成例程,cpu执行完成例程,再把这层的分发函数结束,返回一个值,这个值就是上一层的iocalldriver得到的值,若是底层的分发函数返回成功,则上一层调用iocalldriver的也会返回成功。。然后把状态返回给应用层的调用API。
打印log也是这样的,是会先进入上层分发,然后再进入底层,底层结束IRP,进入完成例程,然后退出底层分发,再退出上层分发。

完成本层未完之事,因为已把IRP复制到下面去了,在下层驱动中的完成例程修改IRP,与我们理解上的在本层完成未了之事是一样的。
2010-1-20 08:44
0
雪    币: 75
活跃值: (623)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
呵呵,没想明白,容我看看再说,
2010-1-20 13:17
0
雪    币: 75
活跃值: (623)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
原以为IoSetCompletionRoutine设置的完成例程被放在了下一层的io_stack_location中,当完成例程被调用时,它的输入参数会对应于下一层的deviceobject,IO_STACK_LOCATION也对应着下一层,所以始终理解不了.

今天特意用windbg跟踪了一下,虽然完成例程被放在了下一层的io_stack_location,但调用它时,它的输入参数依然时本层的deviceobject,它使用的io_stack_location依然对应的是本层的.这样就能理解通了,

谢谢onepc一起讨论
2010-1-20 23:55
0
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
我这里由于机器原因不能双机调试,所以一直用不了windbg,,,没有跟踪很多都不好理解。
2010-1-21 07:52
0
雪    币: 75
活跃值: (623)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
装个vmware沙
2010-1-21 09:19
0
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
呃,机器太老,装了vm之后再装系统装不上。。。我本来的系统已优化得不能再优化了...
2010-1-21 09:27
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我的理解,  irp发起者对应的 current irpStack 是虚的, 而最底层的 设备又不需要completion routine,
所以每层都把comopletion routine 放到下一层, 而最后一层没有
2010-1-21 10:47
0
雪    币: 75
活跃值: (623)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
2010-1-21 16:14
0
雪    币: 75
活跃值: (623)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
我还有点没有想明白:
就是在完成例程中对pending的处理
.....
    if (Irp->PendingReturned)
    {
         IoMarkIrpPending (Irp);
    }
  return STATUS_CONTINUE_COMPLETION;
}
既然此IRP已经被下层用IoCompleteRequest给结束了,完成例程也完成了自己的任务.既然本层所有工作都完成了,该返回上层了..为啥还要把Irp设置成pending?还要让上层的iocalldriver(假设是同步IRP)返回status_pending???
2010-1-21 16:32
0
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
这个当底层在IRP分发涵数里立刻调用iocompleterequest的话那么底层的IRP分发也就是返回成功的,Irp->PendingReturned这个是没置位的,就是说不会执行if里面的。
但是当底层IRP里的IRP没有马上调用iocompleterequest,那么,底层的分发函数就返回pending状态。所以底层的会用一个DPC之类的设成过多久之后再把这个IRP结束掉。这时就会进入完成例程,所以这时才需要用IoMarkIrpPending (Irp);处理pending位。

我想只要是在低层马上结束IRP的话这句不写也可以的,但是异步的话就一定要处理,因为未完成IRP是会返回pending状态
2010-1-21 19:57
0
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
只要是同步没马上结束IRP也是要处理的,只要是马上处理的就不用也可以,还有你说还调用iocalldriver这个,应是当完成例程返回那个值,可以能让本层再控制IRP的吧,这时就可以自己处理IRP或者再发回去给底层处理。
2010-1-21 20:07
0
雪    币: 75
活跃值: (623)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
13
没想到跟踪这个过程的好方法..再琢磨琢磨
2010-1-22 02:36
0
游客
登录 | 注册 方可回帖
返回
//