FreelfAllocated(dx->HidPreparsedData);
FreeIfAllocated(dx->HidSymLinkName.Buffer);
// Initialise Symbolic link names
UNICODE_STRING linkName;
RtlInitUnicodeString(&linkName, SYM_LINK_NAME);
// Remove symbolic link
DebugPrint('Deleting symbolic link XT', &linkName);
IoDeleteSymbolicLink(&linkName);
ObDereferenceObject(dx->HidDevice);
IoDeleteDevice(HidKbdDo);
HidKbdDo = NULL;
}
The HidKbd
However,
The
Listing 23.10 HidKbd GetPreparsedData routine
bool GetPreparsedData(IN PDEVICE_OBJECT HidDevice, OUT PHIDP_PREPARSED_DATA HidPreparsedData) {
HID_COLLECTION_INFORMATION HidCi;
NTSTATUS status = CallHidIoctl(HidDevice, IOCTL_HID_GET_COLLECTION_INFORMATION, &HidCi, sizeof(HidCi));
if (!NT_SUCCESS(status)) {
DebugPrint('IOCTL_HID_GET_COLLECTION_INFORMATION failed %x', status);
return false;
}
DebugPrint('HID attributes: VendorID=%4x, ProductID=%4x, VersionNumber=%4x',
HidCi.VendorID, HidCi.ProductIO, HidCi.VersionNumber);
ULONG PreparsedDatalen = HidCi.DescriptorSize;
DebugPrint('PreparsedDatalen %d', PreparsedDatalen);
HidPreparsedData = (PHIDP_PREPARSED_DATA)ExAllocatePool(NonPagedPool, PreparsedDatalen);
if (HidPreparsedData==NULL) {
DebugPrintMsg('No memory');
return false;
}
status = CallHidIoctl(HidDevice, IOCTL_HID_GET_COLLECTON_DESCRIPTOR, HidPreparsedData, PreparsedDatalen);
if (!NT_SUCCESS(status)) {
DebugPrint('IOCTL_HID_GET_COLLECTION_DESCRIPTOR failed %x', status);
return false;
}
return true;
}
The DDK documentation for the HID class driver read and write handler says that the IRP file object pointer must be valid. HidKbd obtained a file object using
When a user mode application opens a handle to a HidKbd device, the Create IRP handler receives another file object pointer. This same file object pointer is passed in subsequent Read, Write, and Close IRPs, etc.
The HidKbd Create IRP handler,
As HidKbd does not need to process the IRP afterwards, there is no need to set a completion routine.
// Forward IRP to HID class driver device
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(dx->HidDevice, Irp);
The HidKbd Close IRP handler,
A side effect of making the HID class driver open a handle for the device is that Windows 2000 will not let the HID device be removed for the duration. This is a perfectly acceptable behavior.
Reading and Writing Data
Our HID kernel mode client is now finally ready to read and write data.
HidKbd currently only supports reading of input reports. The Read IRP expects the provided buffer to be big enough. For a keyboard-input report, the buffer must be at least nine bytes long. The first byte will be 0, with the eight bytes of the input report in the remaining bytes. HidKbd makes no attempt to analyze the data in the same way as
The main Read IRP handler, HidKbdRead, eventually calls
By default,
Finally, HidKbd runs
I have left out one small part of the story. The DDK says that HID class drivers use Direct I/O for their input and output buffers, not Buffered I/O. Luckily,
Listing 23.11 ReadHidKbdlnputReport routine
NTSTATUS ReadHidKbdInputReport(PFILE_OBJECT FileObject, PVOID Buffer, ULONG& BytesTxd) {
PHIDKBD_DEVICE_EXTENSION dx = (PHIDKBD_DEVICE_EXTENSION)HidKbdDo->DeviceExtension;
BytesTxd = 0;
if (HidKbdDo==NULL) return STATUS_NO_MEDIA_IN_DEVICE;
IO_STATUS_BLOCK IoStatus;
IoStatus.Information = 0;
KEVENT event;
LARGE_INTEGER FilePointer;
FilePointer.QuadPart = 0i64;
// Initialise IRP completion event
KeInitializeEvent(&event, NotificationEvent, FALSE);
PIRP Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, dx->HidDevice,
Buffer, dx->HidInputReportLen, &FilePointer, &event, &IoStatus);
if (Irp==NULL) return STATUS_INSUFFICIENT_RESOURCES;