songybwf
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2004-05-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1578回复:12

ReadCompleteRoutine什么时候调用?

楼主#
更多 发布于:2004-04-22 21:42
我的irp_mj_read里面很简单,就是两句话:
IoSetCompletionRoutine( Irp, ReadCompleteRoutine,NULL, TRUE, TRUE, TRUE );
IoCallDriver( DeviceObject, Irp );

ReadCompleteRoutine也很简单
{
if( Irp->PendingReturned )
{
 IoMarkIrpPending( Irp );
}
DbgPrint(\"Entering Read Complete Routine\\n\",);
return Irp->IoStatus.Status;
}

我用softice跟踪,确实运行了IoSetCompletionRoutine,但为什么
从来没有进到ReadCompleteRoutine里面呢?我哪里错了吗?

最新喜欢:

ljmmaryljmmar...
wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
沙发#
发布于:2004-04-26 15:33
[quote]IoCopyCurrentIrpStackLocationToNext(Irp);

*nextIrpStack = *currentIrpStack;
是一样的,本来就是DDK里的宏而已。

[编辑 -  4/23/04 by  wowocock]


错!

*nextIrpStack = *currentIrpStack;

这行语句会把上层驱动的完成例程设置到你的下层驱动的的IO堆栈,导致上层驱动的完成例程被调用两次,结果是无法预料的。

而IoCopyCurrentIrpStackLocationToNext()则不会这样做,这就是为什么调用这个例程之后还要另外调用IoSetCompletionRoutine()设置完成例程的原因。 [/quote]
#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \\
    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; }
到 CompletionRoutine为止啊,到是没注意,嘿嘿.....
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
deltali
驱动小牛
驱动小牛
  • 注册日期2002-10-25
  • 最后登录2010-07-06
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望23点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-04-23 17:17
也可以不用在IRP_MJ_READ里面加代码,

就在
//
// Copy parameters down to next level in the stack for the driver below us
//
*nextIrpStack = *currentIrpStack;
后面设置一个complete处理函数。这样filemon里面的每个IRP_MJ_xxx处理完后就会进入你的complete处理函数,然后再判断是不是IRP_MJ_READ就可以了
我又来了,生命不息,驱动不止。
slwqw
驱动大牛
驱动大牛
  • 注册日期2002-07-18
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望197点
  • 贡献值0点
  • 好评度147点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-04-23 15:48
IoCopyCurrentIrpStackLocationToNext(Irp);

*nextIrpStack = *currentIrpStack;
是一样的,本来就是DDK里的宏而已。

[编辑 -  4/23/04 by  wowocock]


错!

*nextIrpStack = *currentIrpStack;

这行语句会把上层驱动的完成例程设置到你的下层驱动的的IO堆栈,导致上层驱动的完成例程被调用两次,结果是无法预料的。

而IoCopyCurrentIrpStackLocationToNext()则不会这样做,这就是为什么调用这个例程之后还要另外调用IoSetCompletionRoutine()设置完成例程的原因。
wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
地下室#
发布于:2004-04-23 15:37
IoCopyCurrentIrpStackLocationToNext(Irp);

*nextIrpStack = *currentIrpStack;
是一样的,本来就是DDK里的宏而已。

[编辑 -  4/23/04 by  wowocock]
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
slwqw
驱动大牛
驱动大牛
  • 注册日期2002-07-18
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望197点
  • 贡献值0点
  • 好评度147点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2004-04-23 14:30
ildee说得对,应该这样:

IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine( Irp, ReadCompleteRoutine,NULL, TRUE, TRUE, TRUE );

另外,下面这行语句跟上面的语句相冲突,也删除了吧,

//
// Copy parameters down to next level in the stack for the driver below us
//
*nextIrpStack = *currentIrpStack;
ildee
驱动牛犊
驱动牛犊
  • 注册日期2003-01-16
  • 最后登录2005-01-24
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2004-04-23 12:59
应该先copycurrentirplacationtonext,再iosetcompletionroutine
songybwf
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2004-05-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2004-04-23 12:32
不好意思,我主要是怕贴的代码长反而看不清楚。


分发例程如下:

NTSTATUS
FilemonHookRoutine(
    PDEVICE_OBJECT HookDevice,
    IN PIRP Irp
    )
{
    PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION  nextIrpStack    = IoGetNextIrpStackLocation(Irp);
    PQUERY_DIRECTORY    queryDirectory;
    PFILE_OBJECT        FileObject;
    PHOOK_EXTENSION     hookExt;
    LARGE_INTEGER       dateTime;
    LARGE_INTEGER       perfTime;
    PCHAR               fullPathName = NULL;
    BOOLEAN             hookCompletion, createPath;
    CHAR                controlCodeBuffer[ERRORLEN];
    CHAR                attributeString[ERRORLEN];
    CHAR                optionString[ERRORLEN];
    CHAR                name[PROCNAMELEN];
    ULONG               i;
    ANSI_STRING         directoryFilter;
    PCHAR               queryFilter;
    ULONG               seqNum;
    KIRQL               oldirql;

    //
    // Extract the file object from the IRP
    //
    FileObject = currentIrpStack->FileObject;

    //
    // Point at the device extension, which contains information on which
    // file system this IRP is headed for
    //
    hookExt = HookDevice->DeviceExtension;

    //
    // We note open cases so that when we query the file name
    // we don\'t ask the file system for the name (since it won\'t
    // have seen the file object yet).
    //
    if( currentIrpStack->MajorFunction == IRP_MJ_CREATE ||
        currentIrpStack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE ||
        currentIrpStack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ) {

        //
        // Clear any existing fileobject/name association stored in the
        // hash table
        //
        FilemonFreeHashEntry( FileObject );
        createPath = TRUE;

    } else if( currentIrpStack->MajorFunction == IRP_MJ_CLOSE ) {

        //
        // We treat close as a special case of create for name querying
        // since calling into NTFS during a close can result in a deadlock.
        //
        createPath = TRUE;

    } else if( currentIrpStack->MajorFunction == IRP_MJ_CLEANUP &&
               FileObject->Flags & FO_STREAM_FILE ) {

        //
        // Treat cleanup of stream file objects as special create case, because
        // querying them causes NTFS to screwup on NT 4
        //
        

    } else {

        createPath = FALSE;
    }

    //
    // Allocate a buffer and get the name only if we have to
    //
    if( FilterOn && hookExt->Hooked ) {

        GETPATHNAME( createPath );
    }

    //
    // Only log it if it passes the filter
    //
    if( hookExt->Hooked && fullPathName ) {

        //
        // If measuring absolute time go and get the timestamp.
        //
        KeQuerySystemTime( &dateTime );
        perfTime = KeQueryPerformanceCounter( NULL );

        //
        // We want to watch this IRP complete
        //
        seqNum = (ULONG) -1;
        hookCompletion = FALSE;

        //
        // Determine what function we\'re dealing with
        //
        FilemonGetProcess( name );
        switch( currentIrpStack->MajorFunction ) {

......

        case IRP_MJ_READ:


IoSetCompletionRoutine( Irp, ReadCompleteRoutine,NULL, TRUE, TRUE, TRUE );

/*            if( FilterDef.logreads ) {
                hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                           \"%s\\tIRP_MJ_READ%c\\t%s\\tOffset: %d Length: %d\",
                                           name,
                                           (Irp->Flags & IRP_PAGING_IO) ||
                                                  (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? \'*\' : \' \',
                                           fullPathName,
                                           currentIrpStack->Parameters.Read.ByteOffset.LowPart,
                                           currentIrpStack->Parameters.Read.Length );
            }
*/
            break;

......

}
    //
    // Free the buffer if we have one
    //
    if( fullPathName && fullPathName != InsufficientResources ) {

        ExFreeToNPagedLookasideList( &FullPathLookaside, fullPathName );
    }

    //
    // Copy parameters down to next level in the stack for the driver below us
    //
    *nextIrpStack = *currentIrpStack;

#if DBG
    //
    // If an unload isn\'t in progress, we should register a completion callback
    // so that the IRP\'s return status can be examined.
    //
    KeAcquireSpinLock( &CountMutex, &oldirql );
#endif

    if( !UnloadInProgress && hookCompletion ) {

#if DBG
        //
        // Increment the outstanding IRP count since this IRP will be headed
        // for our completion routine
        //
        FilemonDriver->DriverUnload = NULL;
        OutstandingIRPCount++;
        DbgPrint((\"+%d: %x\\n\", OutstandingIRPCount, Irp ));;
#endif // DBG
        //
        // Grab the time stamp and Log it in the current stack location. This
        // is legal since the stack location is ours, and we\'re done looking at
        // the parameters. This makes it easy to pass this to the completion routine. The
        // DiskPerf example in the NT DDK uses this trick.
        //
        currentIrpStack->Parameters.Read.ByteOffset = perfTime;
        

if(currentIrpStack->MajorFunction == IRP_MJ_READ)
 {
            DbgPrint((\"Enter 1. \\n\"));
 
 }
else
{
  DbgPrint((\"Enter 2. \\n\"));
 IoSetCompletionRoutine( Irp, FilemonHookDone, (void *)seqNum, TRUE, TRUE, TRUE );
}
    } else {


DbgPrint((\"Enter 3. \\n\"));
//
        // Set no completion routine
        //
//        IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, FALSE, FALSE, FALSE );
    }
#if DBG
    KeReleaseSpinLock( &CountMutex, oldirql );
#endif

    //
    // Return the results of the call to the caller
    //
    return IoCallDriver( hookExt->FileSystem, Irp );
}



ReadCompleteRoutine例程如下:

{
if( Irp->PendingReturned )
{
IoMarkIrpPending( Irp );
}
DbgPrint(\"Entering Read Complete Routine\\n\",);
return Irp->IoStatus.Status;
}

我现在能看到DbgPrint((\"Enter 1. \\n\"));的输出却看不到DbgPrint(\"Entering Read Complete Routine\\n\",);的输出.


我没有仔细地看过Filemon的代码,所以你最好把相关代码都贴出来,否则大家是没有空猜来猜去的,又不是在玩捉谜藏游戏。
slwqw
驱动大牛
驱动大牛
  • 注册日期2002-07-18
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望197点
  • 贡献值0点
  • 好评度147点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2004-04-23 08:49
我没有仔细地看过Filemon的代码,所以你最好把相关代码都贴出来,否则大家是没有空猜来猜去的,又不是在玩捉谜藏游戏。
songybwf
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2004-05-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2004-04-23 02:05
我是根据filemon改的。我是在它的irp_mj_read 分发例程里加了上面的两句,然后在filemon设完成例程的地方加了个判断(是irp_mj_read就跳过,否则就不改它设的完成例程)。你所说的这条语句在别的地方设了。    *nextIrpStack = *currentIrpStack;效果应该一样吧?


估计少了一行语句:

IoCopyCurrentIrpStackLocationToNext(Irp);
 
wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
10楼#
发布于:2004-04-22 22:49
呵呵,我估计也是,不过没调整IRP堆栈,没崩溃也是不错的事.
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
slwqw
驱动大牛
驱动大牛
  • 注册日期2002-07-18
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望197点
  • 贡献值0点
  • 好评度147点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2004-04-22 22:40
估计少了一行语句:

IoCopyCurrentIrpStackLocationToNext(Irp);
wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
12楼#
发布于:2004-04-22 22:36
稍微完整点的代码贴出来看看/
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
游客

返回顶部