阅读:1578回复:12
ReadCompleteRoutine什么时候调用?
我的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里面呢?我哪里错了吗? |
|
最新喜欢:![]() |
沙发#
发布于:2004-04-26 15:33
[quote]IoCopyCurrentIrpStackLocationToNext(Irp); 错! *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为止啊,到是没注意,嘿嘿..... |
|
|
板凳#
发布于: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就可以了 |
|
|
地板#
发布于:2004-04-23 15:48
IoCopyCurrentIrpStackLocationToNext(Irp); 错! *nextIrpStack = *currentIrpStack; 这行语句会把上层驱动的完成例程设置到你的下层驱动的的IO堆栈,导致上层驱动的完成例程被调用两次,结果是无法预料的。 而IoCopyCurrentIrpStackLocationToNext()则不会这样做,这就是为什么调用这个例程之后还要另外调用IoSetCompletionRoutine()设置完成例程的原因。 |
|
地下室#
发布于:2004-04-23 15:37
IoCopyCurrentIrpStackLocationToNext(Irp);
和 *nextIrpStack = *currentIrpStack; 是一样的,本来就是DDK里的宏而已。 [编辑 - 4/23/04 by wowocock] |
|
|
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; |
|
6楼#
发布于:2004-04-23 12:59
应该先copycurrentirplacationtonext,再iosetcompletionroutine
|
|
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的代码,所以你最好把相关代码都贴出来,否则大家是没有空猜来猜去的,又不是在玩捉谜藏游戏。 |
|
8楼#
发布于:2004-04-23 08:49
我没有仔细地看过Filemon的代码,所以你最好把相关代码都贴出来,否则大家是没有空猜来猜去的,又不是在玩捉谜藏游戏。
|
|
9楼#
发布于:2004-04-23 02:05
我是根据filemon改的。我是在它的irp_mj_read 分发例程里加了上面的两句,然后在filemon设完成例程的地方加了个判断(是irp_mj_read就跳过,否则就不改它设的完成例程)。你所说的这条语句在别的地方设了。 *nextIrpStack = *currentIrpStack;效果应该一样吧?
估计少了一行语句: |
|
10楼#
发布于:2004-04-22 22:49
呵呵,我估计也是,不过没调整IRP堆栈,没崩溃也是不错的事.
|
|
|
11楼#
发布于:2004-04-22 22:40
估计少了一行语句:
IoCopyCurrentIrpStackLocationToNext(Irp); |
|
12楼#
发布于:2004-04-22 22:36
稍微完整点的代码贴出来看看/
|
|
|