如果需要将IRP异步完成, 一般不会在处理函数中调用IoCompleteRequest函数, 因为调用IoCompleteRequest函数就意味着,该IRP请求处理完成了, 事实上很多时候是需要多次处理, 或者有其他需求的, 这边先谈谈将当前IRP挂起.

挂起意味着,是异步操作, 那么需要等待以后某个时机再处理, 当然这个时机问题的话, 以后会了解到, 目前需要解决的是挂起当前IRP的方法.

下面这个驱动的功能就是这样, 将所有的IRP都挂起, 在最后Win32这边调用CloseHandle的时候再统一处理, 完成那些IRP请求. 一种异步完成IRP的例子. 除了挂起还要取消什么的. 下一篇说.

主要说说这一篇的挂起操作. 挂起其实也很简单, 就是不调用IoCompleteRequest, 改为调用IoMarkIrpPending. 当然这些IRP需要自己用某种手段存放起来, 不然的话回头取就不知道怎么取出来了, 这边用的是系统提供的双向链表了. 调用IoMarkIrpPending以后返回STASTUS_PENDING那么, Win32调用函数这边就会返回ERROR_IO_PENDING, 当然这样并不代表有错误的, 只是IRP还没有完成而已..

这几天兴致不是很高啊, 上代码吧. 这边是用户层的.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
	Windows内核下挂起当前IRP, 在IRP_MJ_CLEANUP中统一完成 3环代码
	编译方法参见makefile. TAB = 8
*/
#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 ), 0; );
		bRet =  WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped1 );

		if ( !bRet & GetLastError() != ERROR_IO_PENDING ) {
			printf( "写入设备失败\n"; );
			return -1;
		}

		RtlFillMemory( byBuf, sizeof( byBuf ), &#39;b&#39; );
		bRet =  WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped2 );

		if ( !bRet &amp;&amp; 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;
}

这边是内核态的代码:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
	Windows内核下挂起当前IRP, 在IRP_MJ_CLEANUP中统一完成 0环代码
	编译方法参见makefile. TAB = 8
*/
#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;
}