From: Thomas Portal <portal.thomas@protonmail.com> WriteFile on a HID output report returns the output report length on Windows, regardless of the transfer length the minidriver reports. hid_device_xfer_report instead forwarded the minidriver count after subtracting the report ID byte, so on a numbered report WriteFile came up one byte short. An application that follows the returned count to drive an upload then stalls; the Elgato Stream Deck image upload does exactly that. Report the output report length on completion instead of adjusting the minidriver count. The dinput test masked this: its mock bus driver returned report_len + 1 and the subtraction cancelled the extra byte. Have the mock return an unrelated length so the test checks that hidclass returns the output report length and not the count the minidriver reported. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59891 Signed-off-by: Thomas Portal <portal.thomas@protonmail.com> --- dlls/dinput/tests/hid.c | 14 +++----------- dlls/hidclass.sys/device.c | 7 ++++--- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 7c42ac54f74..dfd35156f22 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -1427,7 +1427,7 @@ static void test_write_file( HANDLE file, int report_id, ULONG report_len ) .report_id = report_id, .report_len = report_len - (report_id ? 0 : 1), .report_buf = {report_id ? report_id : 0xcd,0xcd,0xcd,0xcd,0xcd}, - .ret_length = 3, + .ret_length = 5, .ret_status = STATUS_SUCCESS, }; @@ -1463,16 +1463,8 @@ static void test_write_file( HANDLE file, int report_id, ULONG report_len ) ret = WriteFile( file, report, report_len, &length, NULL ); } - if (report_id) - { - ok( ret, "WriteFile failed, last error %lu\n", GetLastError() ); - ok( length == 2, "WriteFile wrote %lu\n", length ); - } - else - { - ok( ret, "WriteFile failed, last error %lu\n", GetLastError() ); - ok( length == 3, "WriteFile wrote %lu\n", length ); - } + ok( ret, "WriteFile failed, last error %lu\n", GetLastError() ); + ok( length == report_len, "WriteFile wrote %lu\n", length ); set_hid_expect( file, NULL, 0 ); } diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 5b7a675db7f..4a28ec01344 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -416,7 +416,7 @@ static const WCHAR *find_device_string( const WCHAR *device_id, ULONG index ) struct completion_params { HID_XFER_PACKET packet; - ULONG padding; + ULONG report_len; IRP *irp; }; @@ -428,7 +428,7 @@ static NTSTATUS CALLBACK xfer_completion( DEVICE_OBJECT *device, IRP *irp, void TRACE( "device %p, irp %p, context %p\n", device, irp, context ); orig_irp->IoStatus = irp->IoStatus; - orig_irp->IoStatus.Information -= params->padding; + if (params->report_len) orig_irp->IoStatus.Information = params->report_len; IoCompleteRequest( orig_irp, IO_NO_INCREMENT ); free( params ); @@ -498,7 +498,8 @@ static NTSTATUS hid_device_xfer_report( struct phys_device *pdo, ULONG code, IRP sizeof(params->packet), TRUE, NULL, NULL ); break; case IOCTL_HID_WRITE_REPORT: - params->padding = 1 - offset; + /* WriteFile returns the output report length, not the minidriver count */ + params->report_len = report_len; /* fallthrough */ case IOCTL_HID_SET_FEATURE: case IOCTL_HID_SET_OUTPUT_REPORT: -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11204