From: Robert Gerigk <Robert-Gerigk@online.de> HID child PDOs were created with DeviceType 0 and no characteristics, causing GetFileType() to return FILE_TYPE_DISK instead of FILE_TYPE_UNKNOWN. This broke .NET applications (e.g. ETS6) that use FileStream on HID device handles, as FileStream incorrectly treats FILE_TYPE_DISK handles as seekable files. Set DeviceType to FILE_DEVICE_UNKNOWN and Characteristics to FILE_AUTOGENERATED_DEVICE_NAME to match Windows behavior, and add an IRP_MJ_QUERY_VOLUME_INFORMATION handler to return these values. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59512 --- dlls/hid/tests/device.c | 22 ++++++++++++++++++++++ dlls/hidclass.sys/pnp.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/dlls/hid/tests/device.c b/dlls/hid/tests/device.c index 8b5ff7a0fe7..598d5e8467a 100644 --- a/dlls/hid/tests/device.c +++ b/dlls/hid/tests/device.c @@ -24,6 +24,8 @@ #include "hidusage.h" #include "ddk/hidsdi.h" +#include "winternl.h" + #include "wine/test.h" #define READ_MAX_TIME 5000 @@ -458,9 +460,29 @@ static void test_get_input_report(void) HeapFree(GetProcessHeap(), 0, report); } +static void test_device_file_type(HANDLE device) +{ + FILE_FS_DEVICE_INFORMATION info; + IO_STATUS_BLOCK io; + NTSTATUS status; + DWORD file_type; + + file_type = GetFileType(device); + ok(file_type == FILE_TYPE_UNKNOWN, "Expected FILE_TYPE_UNKNOWN, got %lu\n", file_type); + + memset(&info, 0xcc, sizeof(info)); + memset(&io, 0xcc, sizeof(io)); + status = NtQueryVolumeInformationFile(device, &io, &info, sizeof(info), FileFsDeviceInformation); + ok(status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %lx\n", status); + ok(info.DeviceType == FILE_DEVICE_UNKNOWN, "Expected FILE_DEVICE_UNKNOWN (0x22), got %#lx\n", info.DeviceType); + ok(info.Characteristics == FILE_AUTOGENERATED_DEVICE_NAME, + "Expected FILE_AUTOGENERATED_DEVICE_NAME (0x80), got %#lx\n", info.Characteristics); +} + START_TEST(device) { run_for_each_device(test_device_info); + run_for_each_device(test_device_file_type); test_read_device(); test_get_input_report(); } diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 4774ba2b9fc..d3abbe934fc 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -276,7 +276,8 @@ static NTSTATUS create_child_pdos( minidriver *minidriver, DEVICE_OBJECT *device fdo->base.hid.PhysicalDeviceObject ); RtlInitUnicodeString(&string, pdo_name); - if ((status = IoCreateDevice( device->DriverObject, sizeof(*pdo), &string, 0, 0, FALSE, &child_device ))) + if ((status = IoCreateDevice( device->DriverObject, sizeof(*pdo), &string, + FILE_DEVICE_UNKNOWN, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &child_device ))) { ERR( "Failed to create child PDO, status %#lx.\n", status ); return status; @@ -666,6 +667,37 @@ static NTSTATUS WINAPI driver_close(DEVICE_OBJECT *device, IRP *irp) return pdo_close(device, irp); } +static NTSTATUS WINAPI driver_query_volume(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + NTSTATUS status; + + if (irpsp->Parameters.QueryVolume.FsInformationClass == FileFsDeviceInformation) + { + if (irpsp->Parameters.QueryVolume.Length < sizeof(FILE_FS_DEVICE_INFORMATION)) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + FILE_FS_DEVICE_INFORMATION *info = irp->AssociatedIrp.SystemBuffer; + info->DeviceType = device->DeviceType; + info->Characteristics = device->Characteristics; + irp->IoStatus.Information = sizeof(*info); + status = STATUS_SUCCESS; + } + } + else + { + FIXME("unhandled volume info class %x\n", irpsp->Parameters.QueryVolume.FsInformationClass); + status = STATUS_NOT_IMPLEMENTED; + } + + irp->IoStatus.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return status; +} + static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp) { return pdo_ioctl(device, irp); @@ -715,6 +747,7 @@ NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration) registration->DriverObject->MajorFunction[IRP_MJ_WRITE] = driver_write; registration->DriverObject->MajorFunction[IRP_MJ_CREATE] = driver_create; registration->DriverObject->MajorFunction[IRP_MJ_CLOSE] = driver_close; + registration->DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = driver_query_volume; driver->PNPDispatch = registration->DriverObject->MajorFunction[IRP_MJ_PNP]; registration->DriverObject->MajorFunction[IRP_MJ_PNP] = driver_pnp; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10301