上一篇说的是挂起IRP, 并在挂起IRP的时候将挂起的IRP结束, 还有另外一个办法就是取消IRP, 逐个结束. 这就是传说中的取消IRP请求. 这个取消IRP还是比较有用的, 我们很多时候在打开一个文件的时候, 如果需要等待的时间太长, 发现这个文件本来有不是太有用, 一般就会去点取消按钮. 取消当然需要内核的支持.在内核中如果要支持取消IRP, 那么首先要调用IoSetCancelRoutine, 设置一个取消例程, 这个IoSetCancelRoutine函数也是有两个作用, 如果传递的非NULL值, 那么就是设置取消例程, 如果是NULL, 那么就是删除原来设置的(取消例程).
如果是在内核中需要取消回调例程可以调用IoCancelIrp, 当然Win32调用进入内核也是调用这号例程了, 这号例程内部会调用IoAcquireCancelSpinLock获取自旋锁. 所以取消这个自旋锁的任务留给了取消例程了. 这个非常容易忘记,因为我们自己申请的内存都容易忘记释放了. 更不要说这个是人家申请的, 不过还好. 如果不释放是会崩溃的, 所以要记住这一点.还有了在取消例程中当然就不要干太多的事情了. 因为自旋锁占着茅坑呢..
当然Win32下面的CancelIo比内核里面的就强悍一点了, 其可以一次取消很多以前的IRP. 所有未决的请求都可以取消..这篇其实和上篇是差不多的, 上一篇是挂起IRP, 这里是取消IRP. 还要学习几种处理IRP的手段, 基本上写驱动就是倒腾这个了.. 所以要多学习几种手段了..
关于代码的的逻辑含义我就不说了, 和上篇差不多, 并且也没有加太多东西. 直接上代码吧, 这是用户层的.
/* Windows 内核下取消IRP 3环代码 |
编译方法参见makefile. TAB = 8 |
*/ |
#include <windows.h> |
#include <stdio.h> |
#pragma comment( linker, "/Entry:Jmain" ) |
#pragma comment( linker, "/subsystem:console" ) |
#define SYS_LINK_NAME "\\\\.\\SysCancelIrp" |
//=========================================================================== |
//入口 |
//=========================================================================== |
int Jmain( ) { |
BOOL bRet; |
ULONG dwByteWrite; |
UCHAR ucBuf[10]; |
HANDLE hDevice = INVALID_HANDLE_VALUE; |
OVERLAPPED StOverLapped1 = {0}; |
OVERLAPPED StOverLapped2 = {0}; |
do { |
//打开设备 |
hDevice = CreateFile( SYS_LINK_NAME, GENERIC_READ | GENERIC_WRITE, |
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); |
if ( hDevice == INVALID_HANDLE_VALUE ) { |
printf( "打开设备失败!\n" ); |
break; |
} |
RtlFillMemory( &ucBuf, sizeof(ucBuf), 'a' ); |
bRet = WriteFile( hDevice, ucBuf, sizeof( ucBuf ), &dwByteWrite, &StOverLapped1 ); |
if ( !bRet && GetLastError() != ERROR_IO_PENDING ) { |
printf( "读取设备失败!\n" ); |
break; |
} |
RtlFillMemory( &ucBuf, sizeof(ucBuf), 'b' ); |
bRet = WriteFile( hDevice, &ucBuf, sizeof( ucBuf ), &dwByteWrite, &StOverLapped2 ); |
if ( !bRet && GetLastError() != ERROR_IO_PENDING ) { |
printf( "读取设备失败!\n" ); |
break; |
} |
printf( "打开设备, 并且发送两次IRP请求成功!\n" ); |
Sleep( 2000 ); //迫使程序暂停2秒 |
CancelIo( hDevice ); //创建IRP_MJ_CLEANUP Irp |
} while ( FALSE ); |
if ( hDevice != INVALID_HANDLE_VALUE ) { |
CloseHandle( hDevice ); |
} |
system( "pause" ); |
return 0; |
} |
这边是内核的代码:
/* Windows 内核下取消IRP 0环代码 |
编译方法参见makefile. TAB = 8 |
*/ |
#include <ntddk.h> |
//--------------------------------------------------------------------------- |
#define DEVICE_NAME L"\\Device\\CancelIrp" |
#define SYS_LINK_NAME L"\\??\\SysCancelIrp" |
typedef struct tagDeviceExt { |
PDEVICE_OBJECT pDeviceObj; |
UNICODE_STRING USzDeviceName; |
UNICODE_STRING USzSysLinkName; |
} DEVICE_EXT, *PDEVICE_EXT; |
//=========================================================================== |
//驱动卸载例程 |
//=========================================================================== |
#pragma code_seg( "PAGE" ) |
VOID DriverUnload( PDRIVER_OBJECT pDriverObj ) { |
PDEVICE_EXT pDeviceExt = NULL; |
PDEVICE_OBJECT pNextDeviceObj = NULL; |
pNextDeviceObj = pDriverObj->DeviceObject; |
while( pNextDeviceObj != NULL ) { |
pDeviceExt = pNextDeviceObj->DeviceExtension; |
IoDeleteDevice( pDeviceExt->pDeviceObj ); |
IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName ); |
KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) ); |
pNextDeviceObj = pNextDeviceObj->NextDevice; |
} |
} |
//=========================================================================== |
//所有不关心的IRP处理 |
//=========================================================================== |
NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
PAGED_CODE(); |
pIrp->IoStatus.Information = 0; |
pIrp->IoStatus.Status = STATUS_SUCCESS; |
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); |
return STATUS_SUCCESS; |
} |
//=========================================================================== |
//取消例程(取消例程的时候其实和堆栈差不多. 先进先出) |
//=========================================================================== |
#pragma code_seg() |
VOID CancelIrp( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
ULONG i; |
ULONG ulWriteLength; |
ULONG ulWriteOffset; |
PDEVICE_EXT pDeviceExt = NULL; |
PIO_STACK_LOCATION Stack = NULL; |
PAGED_CODE_LOCKED(); |
pDeviceExt = pDeviceObj->DeviceExtension; |
Stack = IoGetCurrentIrpStackLocation(pIrp); |
//欲读取长度 |
ulWriteLength = Stack->Parameters.Write.Length; |
ulWriteOffset = ( ULONG )Stack->Parameters.Write.ByteOffset.QuadPart; |
for( i = 0; i < ulWriteLength; i++ ) { |
KdPrint( ( "%c\t", *( ( ( UCHAR* )pIrp->AssociatedIrp.SystemBuffer ) + i ) ) ); |
} |
KdPrint(( "\n" )); |
//设置完成状态为STATUS_CANCELLED |
pIrp->IoStatus.Status = STATUS_CANCELLED; |
pIrp->IoStatus.Information = 0; |
//结束IRP请求 |
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); |
//此处释放Cancel自旋锁(注意, 这里不是自己获取的, 但是要释放, 很容易忘却) |
IoReleaseCancelSpinLock( pIrp->CancelIrql ); |
KdPrint( ( "离开取消例程!\n" ) ); |
} |
//=========================================================================== |
//读请求处理 |
//=========================================================================== |
#pragma code_seg( "PAGE" ) |
NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
PDEVICE_EXT pDeviceExt = NULL; |
pDeviceExt = ( PDEVICE_EXT )pDeviceObj->DeviceExtension; |
//设置卸载例程(也可以取消卸载例程) |
IoSetCancelRoutine( pIrp, CancelIrp ); |
//将IRP设置为STATUS_CANCELLED |
pIrp->IoStatus.Information = 0; |
pIrp->IoStatus.Status = STATUS_CANCELLED; |
//将IRP设置为挂起状态 |
IoMarkIrpPending( pIrp ); |
KdPrint( ( "DispatchRead挂起!\n" ) ); |
return STATUS_PENDING; |
} |
//=========================================================================== |
//驱动入口 |
//=========================================================================== |
#pragma code_seg( "INIT" ) |
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) { |
ULONG i; |
NTSTATUS Status; |
PDEVICE_EXT pDeviceExt = NULL; |
PDEVICE_OBJECT pDeviceObj = NULL; |
UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME ); |
UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYS_LINK_NAME ); |
//创建设备 |
Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName, |
FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObj ); |
if ( !NT_SUCCESS( Status ) ) { |
KdPrint( ( "设备创建失败!\n" ) ); |
return Status; |
} |
//创建符号链接 |
Status = IoCreateSymbolicLink( &USzSysLinkName, &USzDeviceName ); |
if ( !NT_SUCCESS( Status ) ) { |
KdPrint( ( "创建符号链接失败!\n" ) ); |
return Status; |
} |
//设置设备扩展和设备属性 |
pDeviceObj->Flags |= DO_BUFFERED_IO; |
pDeviceExt = ( PDEVICE_EXT )pDeviceObj->DeviceExtension; |
pDeviceExt->pDeviceObj = pDeviceObj; |
pDeviceExt->USzDeviceName = USzDeviceName; |
pDeviceExt->USzSysLinkName = USzSysLinkName; |
//设置分发函数 |
for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) { |
pDriverObj->MajorFunction[i] = &DispatchRoutine; |
} |
pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite; |
pDriverObj->DriverUnload = DriverUnload; |
return Status; |
} |
277

被折叠的 条评论
为什么被折叠?



