在入口DriverEntry函数做主要操作
1.AttachSysDevice(pDriverObject, L"\\Device\\KeyboardClass0");
2.取消关联驱动设备对象 pDriverObject->DriverUnload = DetachSysDevice;
3.添加IRP_MJ_READ并且参考代码实现DispatchRead
实例代码如下:
#ifdef __cplusplus
extern "C"
{
#endif
#include
#ifdef __cplusplus
}
#endif
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")
#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")
#define arraysize(p) (sizeof(p)/sizeof((p)[0]))
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT pDevice;
PDEVICE_OBJECT TopOfStack;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//keyboard
#include "ntddkbd.h"
#define KEY_UP 1
#define KEY_DOWN 0
#define LCONTROL ((USHORT)0x1D)
#define CAPS_LOCK ((USHORT)0x3A)
ULONG gC2pKeyCount = 0;
/************************************************************************
* 函数名称:AttachSysDevice
* 功能描述:关联系统驱动设备对象
*************************************************************************/
#pragma INITCODE
NTSTATUS AttachSysDevice (
IN PDRIVER_OBJECT pDriverObject,
IN PCWSTR SourceString)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
UNICODE_STRING devName;
WCHAR messageBuffer[] = L"Ctrl2cap Initialized\n";
UNICODE_STRING messageUnicodeString;
//设备名称
RtlInitUnicodeString(&devName,SourceString);
//创建设备
status = IoCreateDevice( pDriverObject,
sizeof(DEVICE_EXTENSION),
NULL, //不指定设备 在后面进行关联
FILE_DEVICE_KEYBOARD,
0,
FALSE, //非独占
&pDevObj );
if (!NT_SUCCESS(status))
{
return status;
}
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevObj->Flags |= DO_BUFFERED_IO;
pDevObj->Flags &= ~DO_DEVICE_INITIALIZING;
//
//关联设备
//
status = IoAttachDevice( pDevObj, &devName, &pDevExt->TopOfStack );
if( !NT_SUCCESS(status) ) {
KdPrint(("Connect with keyboard failed!\n"));
IoDeleteDevice( pDevObj);
return STATUS_SUCCESS;
}
pDevExt->pDevice = pDevObj;
return STATUS_SUCCESS;
}
/************************************************************************
* 函数名称:DetachSysDevice
* 功能描述:取消关联系统驱动设备对象
*************************************************************************/
#pragma PAGEDCODE
VOID DetachSysDevice (IN PDRIVER_OBJECT pDriverObject)
{
PAGED_CODE();
KdPrint(("Enter DriverUnload\n"));
PDEVICE_OBJECT pNextObj;
pNextObj = pDriverObject->DeviceObject;
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
pNextObj = pNextObj->NextDevice;
//从设备栈中弹出
IoDetachDevice( pDevExt->TopOfStack);
pDevExt->TopOfStack = NULL;
//删除该设备对象
IoDeleteDevice( pDevExt->pDevice );
pDevExt->pDevice = NULL;
//等待其他irp完成任务 避免蓝屏
LARGE_INTEGER lDelay;
//delay some time
lDelay = RtlConvertLongToLargeInteger(100 * -10000);
while (gC2pKeyCount)
{
KdPrint(("DetachSysDevice waiting..\n"));
KeDelayExecutionThread(KernelMode, FALSE, &lDelay);
}
KdPrint(("DetachSysDevice OK!\n"));
return;
}
//----------------------------------------------------------------------
//
// ReadCompleteRoutine
//
//----------------------------------------------------------------------
NTSTATUS ReadCompleteRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIO_STACK_LOCATION IrpSp;
PKEYBOARD_INPUT_DATA KeyData;
int numKeys, i;
//
// Request completed - look at the result.
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
if( NT_SUCCESS( Irp->IoStatus.Status ) ) {
//
// Do caps-lock down and caps-lock up. Note that
// just frobbing the MakeCode handles both the up-key
// and down-key cases since the up/down information is specified
// seperately in the Flags field of the keyboard input data
// (0 means key-down, 1 means key-up).
//
KeyData = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);
for( i = 0; i < numKeys; i++ ) {
KdPrint(("ScanCode: %x-%c", KeyData[i].MakeCode, KeyData[i].MakeCode+11-24+'0'));
KdPrint(("%s\n", KeyData[i].Flags ? "Up" : "Down" ));
if( KeyData[i].MakeCode == CAPS_LOCK) {
KeyData[i].MakeCode = LCONTROL;
}
}
}
//
// Mark the Irp pending if required
//
if( Irp->PendingReturned ) {
IoMarkIrpPending( Irp );
}
gC2pKeyCount --;
return Irp->IoStatus.Status;
}
//----------------------------------------------------------------------
//
//IRP DispatchRead
//
//----------------------------------------------------------------------
NTSTATUS DispatchRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp )
{
PDEVICE_EXTENSION devExt;
PIO_STACK_LOCATION currentIrpStack;
PIO_STACK_LOCATION nextIrpStack;
gC2pKeyCount ++;
//
// Gather our variables.
//
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);
//
// Push params down for keyboard class driver.
//
*nextIrpStack = *currentIrpStack;
//
// Set the completion callback, so we can "frob" the keyboard data.
//
IoSetCompletionRoutine( Irp, ReadCompleteRoutine,
DeviceObject, TRUE, TRUE, TRUE );
//
// Return the results of the call to the keyboard class driver.
//
return IoCallDriver( devExt->TopOfStack, Irp );
}
/************************************************************************
* 函数名称:DriverEntry
* 功能描述:驱动程序入口函数
*************************************************************************/
#pragma INITCODE
extern "C" NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath )
{
NTSTATUS status;
ULONG i;
KdPrint(("Enter DriverEntry\n"));
KdPrint(("listen Key drirver!\n"));
//关联驱动设备对象
status = AttachSysDevice(pDriverObject, L"\\Device\\KeyboardClass0");
//取消关联驱动设备对象
pDriverObject->DriverUnload = DetachSysDevice;
//IRP read
pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
KdPrint(("DriverEntry end\n"));
return status;
}
注意事项:
在取消驱动关联的时候需要做个等待
//等待其他irp完成任务 避免蓝屏LARGE_INTEGER lDelay ;//delay some timelDelay = RtlConvertLongToLargeInteger ( 100 * - 10000 );while ( gC2pKeyCount ){KdPrint (( "DetachSysDevice waiting.. \n " ));KeDelayExecutionThread ( KernelMode , FALSE , & lDelay );}