这个系统给的StartIo虽然好用, 但是很多时候我们还是需要使用自定义的StartIo例程的. 因为系统提供的只能使用一个队列.如果是我们自己建立的话, 可以建立多个队列. 灵活性高, 但是稍微复杂些. 其实要说复杂也不尽然, 用那个系统的时候感觉不是很好,因为封装的时候不给力, 还需要在我们自己的函数中帮系统做一些事情.我倒. 还是这个好, 想建立几个队列就几个队列. 而且代码也不是那么的复杂. 也就是几个函数的调用了!

自定义的StartIo例程的话需要程序员自己维护Irp队列, 这样程序员的话可以维护多个队列, 分别对应不同的Irp请求. 首先要搞这个自定义StartIo的话, 要搞个结构KDEVICE_QUEUE, 放在设备扩展里面就可以了. 如果想维护多个, 那么多放几个结构就可以了. 在DriverEntry里面调用keInitializeDeviceQueue函数初始化队列.当然有队列的话, 需要插入, 删除. 插入是KeInsertDeviceQueue, 还有个KeRemoveDeviceQueue删除队列中的元素,.

当然在编写分发函数的时候, 在派遣例程中要调用IoMarkIrpPending挂起当前的Irp.然后准备将Irp进入队列, 当然在进入队列之前需要将当前IRQL提升至DISPATCH_LEVEL.这个需要记得, 不要忘记, 然后在调用KeInsertDeviceQueue函数的时候如果返回FALSE的话, 表示队列已经满了, 需要开始调用自定义的StartIo例程了. 下面的代码就是这样做的.

那么在自定义的StartIo例程中, 处理传进StartIo中的Irp, 然后枚举队列中的Irp.依次出队列, 处理!那么自定义的StartIo就那么多东西了, 看代码吧, 这边是用户态的代码:
 

  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
/*	Windows 内核下StartIo例程试验 3环代码
	编译方法参见makefile. TAB = 8
*/
#include <stdio.h>
#include <windows.h>
 
#pragma comment( linker, "/Entry:Jmain" )
#pragma comment( linker, "/subsystem:console" )
 
#define DEVICE_NAME	"\\\\.\\SysLinkCustomStartIo"
//===========================================================================
//线程过程, 向设备发送15次, 写入请求
//===========================================================================
DWORD __stdcall ThreadProc( PVOID pContext ) {
	UCHAR ucBuf[10];
	ULONG i, j;
	DWORD dwByteWrite;
	BOOL bRet;
	OVERLAPPED StOverlapped[15] = {0};
	HANDLE hEvent[15] = {0};
 
	__try {
		for( i = 0; i < sizeof( StOverlapped ) / sizeof( StOverlapped[0] ); i++ ) {
 
			StOverlapped[i].hEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
			if ( !StOverlapped[i].hEvent ) {
				printf( "创建同步事件失败!\n" );
				return -1;
			}
		}
 
		for( i = 0; i < sizeof( StOverlapped ) / sizeof( StOverlapped[0] ); i++ ) {
			hEvent[i] = StOverlapped[i].hEvent;
		}
 
		Sleep( 1000 );
		for( i = 0; i < sizeof( StOverlapped ) / sizeof( StOverlapped[0] ); i++ ) {
 
			RtlFillMemory( ucBuf, sizeof( ucBuf ), i + 'a' );
 
			bRet = WriteFile( *( PHANDLE )pContext, ucBuf, sizeof( ucBuf ),
					  &dwByteWrite, &StOverlapped[i]  );
 
			if ( !bRet && GetLastError() != ERROR_IO_PENDING ) {
				printf( "写入设备失败!\n" );
				return -1;
			} else {
				for( j = 0; j < sizeof( ucBuf ); j++ ) {
					printf( "%c\t", ucBuf[j] );
				}
 
				printf( "\n" );
			}
		}
 
		//这个复杂度加了一些中间有可能还会有取消IRP的出现
		//CancelIo(*(PHANDLE)pContext);
		WaitForMultipleObjects( sizeof( StOverlapped ) / sizeof( StOverlapped[0] ),
					&hEvent[0], TRUE, INFINITE );
 
		printf( "设备处理完毕!\n" );
 
	} __finally {
		for( i = 0; i < sizeof( hEvent ) / sizeof( hEvent[0] ); i++ ) {
			if ( StOverlapped[i].hEvent ) {
				CloseHandle( StOverlapped[i].hEvent );
			}
		}
	}
 
	return 0;
}
//===========================================================================
int Jmain( ) {
	HANDLE hDevice = NULL;
	HANDLE hThead[2] = {0};
	DWORD dwTemp;
 
	do {
		hDevice = CreateFile( DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL,
			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
 
		if ( hDevice == INVALID_HANDLE_VALUE ) {
			printf( "打开设备失败\n" );
			break;
		}
 
		hThead[0] = CreateThread( NULL, 0, &ThreadProc, &hDevice, 0, &dwTemp );
 
		if ( !hThead[0] ) {
			printf( "创建线程1失败!\n" );
			break;
		} else {
			printf( "创建线程1成功, 线程1已经开始运行!\n" );
		}
 
		hThead[1] = CreateThread( NULL, 0, &ThreadProc, &hDevice, 0, &dwTemp );
 
		if ( !hThead[1] ) {
			printf( "创建线程2失败!\n" );
			break;
		} else {
			printf( "创建线程2成功, 线程2已经开始运行!\n" );
		}
 
		printf( "主线程开始等待两个线程返回!\n" );
 
		WaitForMultipleObjects( 2, hThead, TRUE, INFINITE );
		printf( "两个线程都已经返回!\n" );
 
	} while ( FALSE );
 
//---------------------------------------------------------------------------
	if ( hDevice ) {
		CloseHandle( hDevice );
	}
	if ( hThead[0] ) {
		CloseHandle( hThead[0] );
	}
	if ( hThead[1] ) {
		CloseHandle( hThead[1] );
	}
 
	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
202
203
204
205
206
207
/*      Windows 内核下自定义StartIo 3环代码
        编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>
 
#define DEVICE_NAME	L"\\Device\\CustomStartIo"
#define SYSLINK_NAME	L"\\??\\SysLinkCustomStartIo"
 
typedef struct tagDevice_Ext {
	KDEVICE_QUEUE DeviceQueue;		//设备队列
	PDEVICE_OBJECT pDeviceObj;
	UNICODE_STRING USzDeviceName;
	UNICODE_STRING USzSysLinkName;
} DEVICE_EXT, *PDEVICE_EXT;
//===========================================================================
//驱动卸载例程
//===========================================================================
#pragma code_seg( "PAGE" )
VOID DriverUnload( PDRIVER_OBJECT pDriverObj ) {
	PDEVICE_EXT pDeviceObj;
	PDEVICE_OBJECT pNextDeviceObj = NULL;
 
	pNextDeviceObj = pDriverObj->DeviceObject;
 
	while ( pNextDeviceObj != NULL ) {
		pDeviceObj = pNextDeviceObj->DeviceExtension;
 
		IoDeleteDevice( pDeviceObj->pDeviceObj );
		IoDeleteSymbolicLink( &pDeviceObj->USzSysLinkName );
 
		KdPrint( ( "删除%wZ设备成功!\n", &pDeviceObj->USzDeviceName ) );
 
		pNextDeviceObj = pNextDeviceObj->NextDevice;
	}
}
//===========================================================================
//所有不关心的Irp处理例程
//===========================================================================
#pragma code_seg( "PAGE" )
NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
 
	pIrp->IoStatus.Information = 0;
	pIrp->IoStatus.Status = STATUS_SUCCESS;
 
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return STATUS_SUCCESS;
}
//===========================================================================
//自定义的StartIo例程
//===========================================================================
#pragma code_seg( )
VOID CustomStartIo( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	PIRP NewIrp = NULL;
	KEVENT Event;
	ULONG ulWriteLen, i;
	LARGE_INTEGER liTimeOut;
	PDEVICE_EXT pDeviceExt = NULL;
	PIO_STACK_LOCATION Stack = NULL;
	PKDEVICE_QUEUE_ENTRY pQueue = NULL;
 
	PAGED_CODE_LOCKED();
 
	pDeviceExt = ( PDEVICE_EXT )pDeviceObj->DeviceExtension;
	NewIrp = pIrp;
 
	do {
 
//---------------------------------------------------------------------------
		//打印用户层传递的数据
//---------------------------------------------------------------------------
		KeInitializeEvent( &Event, NotificationEvent, FALSE );
 
		//等3秒
		liTimeOut.QuadPart = -3 * 1000 * 1000 * 10;
 
		//定义一个3秒的延时,主要是为了模拟该IRP操作需要大概3秒左右时间
		KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, &liTimeOut );
 
		Stack = IoGetCurrentIrpStackLocation( NewIrp );
 
		ulWriteLen = Stack->Parameters.Write.Length;
 
		for( i = 0; i < ulWriteLen; i++ ) {
			KdPrint( ( "%c\t",
				   *( ( UCHAR* )( NewIrp->AssociatedIrp.SystemBuffer ) ) ) );
		}
		KdPrint( ( "\n" ) );
//---------------------------------------------------------------------------
		NewIrp->IoStatus.Status = STATUS_SUCCESS;
		NewIrp->IoStatus.Information = 0;
		IoCompleteRequest( NewIrp, IO_NO_INCREMENT );
		KdPrint( ( "CustomStartIo调用一次:%x\n", pQueue ) );
 
		//将存放的Irp出队列
		pQueue = KeRemoveDeviceQueue( &pDeviceExt->DeviceQueue );
 
		//一直处理到队列为空为止
		if ( pQueue == NULL ) {
			break;
		}
 
		NewIrp = CONTAINING_RECORD( pQueue, IRP,
					    Tail.Overlay.DeviceQueueEntry );
	} while( TRUE );
}
//===========================================================================
//取消例程
//===========================================================================
VOID OnCancelIRP( PDEVICE_OBJECT DeviceObject, PIRP Irp  ) {
 
	//释放Cancel自旋锁
	IoReleaseCancelSpinLock( Irp->CancelIrql );
 
	//设置完成状态为STATUS_CANCELLED
	Irp->IoStatus.Status = STATUS_CANCELLED;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest( Irp, IO_NO_INCREMENT );
 
	KdPrint( ( "离开取消例程\n" ) );
}
//===========================================================================
//写入请求处理
//===========================================================================
#pragma code_seg( "PAGE" )
NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	KIRQL OldIrql;
	BOOLEAN bRet;
	PDEVICE_EXT pDeviceExt = NULL;
 
	PAGED_CODE();
 
	pDeviceExt = ( PDEVICE_EXT )pDeviceObj->DeviceExtension;
 
	//将IRP设置为挂起
	IoMarkIrpPending( pIrp );
 
	//设置取消例程
	IoSetCancelRoutine( pIrp, OnCancelIRP );
 
	//提升IRP至DISPATCH_LEVEL
	KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
 
	KdPrint( ( "DispatchWrite设备扩展指针:%x\n",
		   &pIrp->Tail.Overlay.DeviceQueueEntry ) );
 
	//如果KeInsertDeviceQueue返回FALSE的时候,表明Irp没有插入到
	//队列, 而是需要立即被结束
	bRet = KeInsertDeviceQueue( &pDeviceExt->DeviceQueue,
				    &pIrp->Tail.Overlay.DeviceQueueEntry );
	if ( !bRet ) {
		KdPrint( ( "调用CustomStartIo例程!\n" ) );
 
		//调用自定义StartIo例程.
		CustomStartIo( pDeviceObj, pIrp );
	}
 
	//将IRP降至原来IRQL
	KeLowerIrql( OldIrql );
 
	//返回pending状态
	return STATUS_PENDING;
}
//===========================================================================
//驱动入口
//===========================================================================
#pragma code_seg( "INIT" )
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath ) {
	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( SYSLINK_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" ) );
		IoDetachDevice( pDeviceObj );
		return Status;
	}
 
	//设置设备属性, 设备扩展
	pDeviceObj->Flags |= DO_BUFFERED_IO;
	pDeviceExt = pDeviceObj->DeviceExtension;
	pDeviceExt->pDeviceObj = pDeviceObj;
	pDeviceExt->USzDeviceName = USzDeviceName;
	pDeviceExt->USzSysLinkName = USzSysLinkName;
 
	//初始化设备队列(自己实现StartIo)
	RtlZeroMemory( &pDeviceExt->DeviceQueue, sizeof( pDeviceExt->DeviceQueue ) );
	KeInitializeDeviceQueue( &pDeviceExt->DeviceQueue );
 
	for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
		pDriverObj->MajorFunction[i] = &DispatchRoutine;
	}
	pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;
	pDriverObj->DriverUnload = &DriverUnload;
 
	return Status;
}