挂起当前IRP
如果需要将IRP异步完成, 一般不会在处理函数中调用IoCompleteRequest函数, 因为调用IoCompleteRequest函数就意味着,该IRP请求处理完成了, 事实上很多时候是需要多次处理, 或者有其他需求的, 这边先谈谈将当前IRP挂起.
挂起意味着,是异步操作, 那么需要等待以后某个时机再处理, 当然这个时机问题的话, 以后会了解到, 目前需要解决的是挂起当前IRP的方法.
下面这个驱动的功能就是这样, 将所有的IRP都挂起, 在最后Win32这边调用CloseHandle的时候再统一处理, 完成那些IRP请求. 一种异步完成IRP的例子. 除了挂起还要取消什么的. 下一篇说.
主要说说这一篇的挂起操作. 挂起其实也很简单, 就是不调用IoCompleteRequest, 改为调用IoMarkIrpPending. 当然这些IRP需要自己用某种手段存放起来, 不然的话回头取就不知道怎么取出来了, 这边用的是系统提供的双向链表了. 调用IoMarkIrpPending以后返回STASTUS_PENDING那么, Win32调用函数这边就会返回ERROR_IO_PENDING, 当然这样并不代表有错误的, 只是IRP还没有完成而已..
这边是用户层的.
#include <stdio.h>
#include <windows.h>
#pragma comment( linker, "/Entry:Jmain") #define SYS_LINK_NAME \\\\.\\SysLinkPendingIrp; //=========================================================================== //线程等待函数 //=========================================================================== DWORD WINAPI ThreadProc( LPVOID lpParameter ) { HANDLE hEvent; hEvent = *( HANDLE* )lpParameter; printf( "线程开始进入等待状态!\n ); WaitForSingleObject( hEvent, INFINITE ); ExitThread( 0 ); } //=========================================================================== //用户层的启动函数 //=========================================================================== int __stdcall Jmain( int argc, char* argv[] ) { HANDLE hFile = 0; BOOL bRet; DWORD dwByteWrite; HANDLE hThread[2] = {0}; DWORD dwThreadId[2]; BYTE byBuf[10]; OVERLAPPED StOverLapped1 = {0}; OVERLAPPED StOverLapped2 = {0}; __try { //异步打开设备. 下面操作的函数都是异步的 hFile = CreateFile( SYS_LINK_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0 ); if ( hFile == INVALID_HANDLE_VALUE ) { printf( "打开设备失败!\n ); return -1; } //创建两个事件用于异步读取文件 StOverLapped1.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); StOverLapped2.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); //创建两个线程等待内核设置事件, 不然看不到效果 hThread[0] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped1.hEvent, 0, &dwThreadId[0] ); if ( hThread[0] == NULL ) { printf( "创建线程1失败!\n ); return -1; } hThread[1] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped2.hEvent, 0, &dwThreadId[1] ); if ( hThread[1] == NULL ) { printf( "创建线程2失败!\n ); } Sleep( 1000 ); //--------------------------------------------------------------------------- //向设备发送了两次写入请求, 都会被挂起. //--------------------------------------------------------------------------- RtlFillMemory( byBuf, sizeof( byBuf ), 'a'; ); bRet = WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped1 ); if ( !bRet && GetLastError() != ERROR_IO_PENDING ) { printf( "写入设备失败\n"; ); return -1; } RtlFillMemory( byBuf, sizeof( byBuf ), 'b' ); bRet = WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped2 ); if ( !bRet && GetLastError() != ERROR_IO_PENDING ) { printf( "写入设备失败\n" ); return -1; } if ( hFile ) { CloseHandle( hFile ); } //等待多个对象返回(必须同时返回) WaitForMultipleObjects( 2, hThread, TRUE, INFINITE ); printf( "两个对象都已经返回!\n"; ); //--------------------------------------------------------------------------- } __finally { if ( hThread[0] ) { CloseHandle( hThread[0] ); } if ( hThread[1] ) { CloseHandle( hThread[1] ); } if ( StOverLapped1.hEvent ) { CloseHandle( StOverLapped1.hEvent ); } if ( StOverLapped2.hEvent ) { CloseHandle( StOverLapped2.hEvent ); } if ( hFile ) { CloseHandle( hFile ); } system( "pause" ); } return 0; }
这是内核代码
#include<ntddk.h> #define DEVICE_NAME L"\\Device\\DevPendingIrp"; #define SYS_LINK_NAME L"\\??\\SysLinkPendingIrp" //--------------------------------------------------------------------------- typedef struct tagDevice_Ext { PDEVICE_OBJECT pDeviceObj; PLIST_ENTRY pIrpListHead; //链表头结点, 用于存放IRP请求 UNICODE_STRING USzDeviceName; UNICODE_STRING USzSysLinkName; } DEVICE_EXT, *PDEVICE_EXT; typedef struct Irp_Entry { PIRP pIRP; LIST_ENTRY ListEntry; } IRP_ENTRY, *PIRP_ENTRY; //=========================================================================== //驱动卸载例程 //=========================================================================== #pragma code_seg( "PAGE" ) VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) { PDEVICE_EXT pDeviceExt = NULL; PDEVICE_OBJECT pNextDevice = NULL; PAGED_CODE(); pNextDevice = pDriverObj->DeviceObject; while ( pNextDevice != NULL ) { pDeviceExt = pNextDevice->DeviceExtension; IoDeleteDevice( pDeviceExt->pDeviceObj ); IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName ); KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) ); pNextDevice = pNextDevice->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; } //=========================================================================== //IRP_MJ_WRITE的处理, 将所有的IRP都返回为pending状态 //=========================================================================== NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { PDEVICE_EXT pDeviceExt = NULL; PIRP_ENTRY pIrpEntry = NULL; PAGED_CODE(); pDeviceExt = pDeviceObj->DeviceExtension; ASSERT( pDeviceExt != NULL ); pIrpEntry = ( PIRP_ENTRY )ExAllocatePool( PagedPool, sizeof( IRP_ENTRY ) ); ASSERT ( pIrpEntry != NULL ); pIrpEntry->pIRP = pIrp; //插入队列 InsertHeadList( pDeviceExt->pIrpListHead, &pIrpEntry->ListEntry ); //将IRP设置为挂起 IoMarkIrpPending( pIrp ); KdPrint( ( "在IRP_MJ_WRITE请求中将IRP挂起!\n" ) ); //返回pending状态 return STATUS_PENDING; } //=========================================================================== //将未决的写入请求完成 //=========================================================================== NTSTATUS Write_CompleteRequest( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { ULONG i; ULONG ulWriteLength; ULONG ulWriteOffset; PIO_STACK_LOCATION WriteStack = NULL; PAGED_CODE(); WriteStack = IoGetCurrentIrpStackLocation( pIrp ); //欲写入的长度, 偏移 ulWriteLength = WriteStack->Parameters.Write.Length; ulWriteOffset = ( ULONG )WriteStack->Parameters.Write.ByteOffset.QuadPart; for( i = 0; i < ulWriteLength; i++ ) { KdPrint( ( "%c\t", *( ( ( UCHAR* )pIrp->AssociatedIrp.SystemBuffer ) + i ) ) ); } KdPrint( ( "\n" ) ); //简单的完成IRP请求 pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = ulWriteLength; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint( ( "写入请求处理完毕!\n" ) ); return STATUS_SUCCESS; } //=========================================================================== //IRP_MJ_CLEANUP IRP的处理, 将IRP_MJ_WRITE未决的IRP全部处理下 //=========================================================================== NTSTATUS DispatchCleanUp( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL; PIRP_ENTRY pIrpEntry = NULL; PLIST_ENTRY pListEntry = NULL; PAGED_CODE(); pDeviceExt = ( PDEVICE_EXT ) pDeviceObj->DeviceExtension; Status = STATUS_UNSUCCESSFUL; for( ; !IsListEmpty( pDeviceExt->pIrpListHead ); pIrpEntry = NULL ) { pListEntry = RemoveTailList( pDeviceExt->pIrpListHead ); //获取IRP的数据指针 pIrpEntry = CONTAINING_RECORD( pListEntry, IRP_ENTRY, ListEntry ); if ( !pIrpEntry ) { KdPrint( ( "获取结点数据失败!\n" ) ); Status = STATUS_UNSUCCESSFUL; } else { //完成写入请求 Status = Write_CompleteRequest( pDeviceObj, pIrpEntry->pIRP ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "完成写入请求时失败!\n" ) ); } ExFreePool( pIrpEntry ); KdPrint( ( "未决请求处理完成!\n" ) ); } } //处理IRP_MJ_CLEANUP自身的IRP请求 pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); return Status; } //=========================================================================== //驱动程序的入口函数 //=========================================================================== #pragma code_seg( "INIT" ) NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) { ULONG i; NTSTATUS Status; PDEVICE_OBJECT pDevice = NULL; PDEVICE_EXT pDeviceExt = NULL; UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME ); UNICODE_STRING UszSysLink = RTL_CONSTANT_STRING( SYS_LINK_NAME ); Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "创建设备失败!\n" ) ); return Status; } Status = IoCreateSymbolicLink( &UszSysLink, &USzDeviceName ); if ( !NT_SUCCESS( Status ) ) { IoDeleteDevice( pDevice ); KdPrint( ( "创建符号链接失败!\n" ) ); return Status; } //带缓冲区的IO方式 pDevice->Flags |= DO_BUFFERED_IO; pDeviceExt = pDevice->DeviceExtension; pDeviceExt->pDeviceObj = pDevice; pDeviceExt->USzDeviceName = USzDeviceName; pDeviceExt->USzSysLinkName = UszSysLink; //初始化链表头结点 pDeviceExt->pIrpListHead = ( PLIST_ENTRY )ExAllocatePool( PagedPool, sizeof( LIST_ENTRY ) ); InitializeListHead( pDeviceExt->pIrpListHead ); //设置分发函数, 驱动卸载函数 for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) { pDriverObj->MajorFunction[i] = &DispatchRoutine; } pDriverObj->DriverUnload = &DriverUnLoad; pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite; pDriverObj->MajorFunction[IRP_MJ_CLEANUP] = &DispatchCleanUp; return Status; }