Windows 98/Me Compatibility Notes
The footprint of history is heavy on the HID architecture in Windows 98/Me because of the necessity of supporting legacy methods of handling keyboards, mice, and joysticks. In general, it s been my experience that each new attempt to port a working HID minidriver from Windows XP has provided new opportunities for learning and reverse engineering. I plainly don t know everything there is to know in this area, but I ll describe two situations I encountered and how I dealt with them.
Handling IRP_MN_QUERY_ID
If you re writing a minidriver for fake hardware, such as HIDFAKE attempts to do, you must special-case the handling of IRP_MN_QUERY_ID. Left to itself, the root enumerator succeeds this IRP but provides a NULL list of identifiers. HIDCLASS then induces a crash deep in the Virtual Machine Manager (VMM). Here s the code in HIDFAKE to cope with this problem:
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) { PDEVICE_EXTENSION pdx = PDX(fdo); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); if (win98 && stack->MinorFunction == IRP_MN_QUERY_ID && !NT_SUCCESS(Irp->IoStatus.Status)) { PWCHAR idstring; switch (stack->Parameters.QueryId.IdType) { case BusQueryInstanceID: idstring = L"0000"; break; case BusQueryDeviceID: idstring = L"ROOT\\*WCO0D01"; break; case BusQueryHardwareIDs: idstring = L"*WCO0D01"; break; default: return CompleteRequest(Irp); } ULONG nchars = wcslen(idstring); ULONG size = (nchars + 2) * sizeof(WCHAR); PWCHAR id = (PWCHAR) ExAllocatePool(PagedPool, size); if (!id) return CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES); wcscpy(id, idstring); id[nchars + 1] = 0; return CompleteRequest(Irp, STATUS_SUCCESS, (ULONG_PTR) id); } return GenericDispatchPnp(PDX(fdo)->pgx, Irp); }
(Note the use of two override versions of my CompleteRequest helper here.)
Actually, you need to do something special with the BusQueryHardware IDs even in Windows XP because HIDCLASS omits the creation of compatible IDs if the bus driver fails the request, which the root enumerator will do. You can t create a fake device of one of the standard classes unless you know this trick.
Joysticks
In Windows, there are two different code paths for interpreting the axis and button information for a joystick. One code path relies on the HID descriptor. Another relies on settings in the OEM registry key. If these code paths don t produce consistent results, you end up with a nonfunctional joystick in that every attempt to read its position generates an error. I know of no way except trial and error to get past this problem. The one time I had to do it for a client, I ended up writing an elaborate HID simulator that we could quickly program to create new joystick devices with specified attributes. After some number of iterations, we ended up with a working device. I d be hard pressed to reproduce the effort.