From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/dinput.c | 9 +- dlls/dinput/joystick_hid.c | 197 ++++++++++++++++------------------ dlls/dinput/tests/hotplug.c | 2 +- dlls/dinput/tests/joystick8.c | 63 ++++------- 4 files changed, 126 insertions(+), 145 deletions(-) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index 1695221d3a6..1670f0421f0 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -282,7 +282,14 @@ static HRESULT WINAPI dinput7_CreateDeviceEx( IDirectInput7W *iface, const GUID if (IsEqualGUID( &GUID_SysKeyboard, guid )) hr = keyboard_create_device( impl, guid, &device ); else if (IsEqualGUID( &GUID_SysMouse, guid )) hr = mouse_create_device( impl, guid, &device ); - else hr = hid_joystick_create_device( impl, guid, &device ); + else + { + if ((hr = hid_joystick_create_device( impl, guid, &device )) == DIERR_DEVICENOTREG) + { + hid_joystick_refresh_devices(); + hr = hid_joystick_create_device( impl, guid, &device ); + } + } if (FAILED(hr)) return hr; diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index e297f393a60..ca99c1af14f 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -51,7 +51,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 ); -DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 ); DEFINE_GUID( device_path_guid, 0x00000000, 0x0000, 0x0000, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf8 ); /* @@ -228,9 +227,69 @@ static void set_joystick_instance_in_registry( struct joystick_instance *instanc RegCloseKey( dev_key ); } -/* Need to enter the mutex to access this list. */ +static CRITICAL_SECTION joystick_cache_cs; +static CRITICAL_SECTION_DEBUG joystick_cache_cs_debug = +{ + 0, 0, &joystick_cache_cs, + { &joystick_cache_cs_debug.ProcessLocksList, &joystick_cache_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": joystick_cache_cs") } +}; +static CRITICAL_SECTION joystick_cache_cs = { &joystick_cache_cs_debug, -1, 0, 0, 0, 0 }; + +/* Need to enter the CS to access this list. */ static struct list joystick_cache = LIST_INIT(joystick_cache); +static BOOL hid_joystick_cache_get_instance_from_guid(const GUID *guid, WCHAR *dev_path, GUID *guid_instance) +{ + struct joystick_instance *inst; + BOOL ret_val = FALSE; + + EnterCriticalSection( &joystick_cache_cs ); + LIST_FOR_EACH_ENTRY( inst, &joystick_cache, struct joystick_instance, entry ) + { + GUID guid_product = dinput_pidvid_guid; + + guid_product.Data1 = MAKELONG( inst->vid, inst->pid); + if (IsEqualGUID( &inst->guid, guid ) || IsEqualGUID( &guid_product, guid )) + { + wcscpy( dev_path, inst->dev_path ); + *guid_instance = inst->guid; + ret_val = TRUE; + break; + } + } + LeaveCriticalSection( &joystick_cache_cs ); + + return ret_val; +} + +static BOOL hid_joystick_cache_get_instance_from_index(unsigned int index, WCHAR *dev_path, GUID *guid_instance) +{ + BOOL ret_val = FALSE; + + EnterCriticalSection( &joystick_cache_cs ); + if (list_count( &joystick_cache ) > index) + { + struct joystick_instance *inst; + unsigned int i = 0; + + LIST_FOR_EACH_ENTRY( inst, &joystick_cache, struct joystick_instance, entry ) + { + if (index == i) + { + wcscpy( dev_path, inst->dev_path ); + *guid_instance = inst->guid; + ret_val = TRUE; + break; + } + i++; + } + } + LeaveCriticalSection( &joystick_cache_cs ); + + return ret_val; +} + /* * Read current joystick instances in the registry, update any instances * already in the local cache, and remove any instances in the local cache @@ -1711,18 +1770,17 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, BOOL has_accelerator, has_brake, has_clutch, has_z, has_pov; PHIDP_PREPARSED_DATA preparsed_data = NULL; HIDP_LINK_COLLECTION_NODE nodes[256]; - DWORD type, size, button_count = 0; + DWORD type, button_count = 0; HIDP_BUTTON_CAPS buttons[10]; HIDP_VALUE_CAPS value; HANDLE device_file; ULONG node_count; NTSTATUS status; - UINT32 handle; USHORT count; device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, 0 ); - if (device_file == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG; + if (device_file == INVALID_HANDLE_VALUE) return E_FAIL; if (!HidD_GetPreparsedData( device_file, &preparsed_data )) goto failed; if (!HidD_GetAttributes( device_file, attrs )) goto failed; @@ -1740,14 +1798,7 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, if (!HidD_GetProductString( device_file, instance->tszInstanceName, MAX_PATH * sizeof(WCHAR) )) goto failed; if (!HidD_GetProductString( device_file, instance->tszProductName, MAX_PATH * sizeof(WCHAR) )) goto failed; - if (!DeviceIoControl( device_file, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE, NULL, 0, &handle, sizeof(handle), &size, NULL )) - { - ERR( "failed to get raw input handle, error %lu\n", GetLastError() ); - goto failed; - } - - instance->guidInstance = hid_joystick_guid; - instance->guidInstance.Data1 ^= handle; + instance->guidInstance = GUID_NULL; instance->guidProduct = dinput_pidvid_guid; instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID ); instance->guidFFDriver = GUID_NULL; @@ -1941,6 +1992,7 @@ HRESULT hid_joystick_refresh_devices( void ) hr = hid_joystick_get_class_dev_iface_list( &hid, NULL, &hid_list ); if (FAILED(hr)) return hr; + EnterCriticalSection( &joystick_cache_cs ); get_dinput_reg_mutex(); hid_joystick_cache_update_from_registry(); @@ -2029,6 +2081,7 @@ HRESULT hid_joystick_refresh_devices( void ) exit: release_dinput_reg_mutex(); + LeaveCriticalSection( &joystick_cache_cs ); LIST_FOR_EACH_ENTRY_SAFE( cur, cur2, &cur_joysticks, struct joystick_instance, entry ) { list_remove( &cur->entry ); @@ -2038,86 +2091,12 @@ exit: return hr; } -static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEINSTANCEW *instance, - WCHAR *device_path, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed, - HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DWORD version ) -{ - char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)]; - SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer; - SP_DEVICE_INTERFACE_DATA iface = {.cbSize = sizeof(iface)}; - SP_DEVINFO_DATA devinfo = {.cbSize = sizeof(devinfo)}; - WCHAR device_id[MAX_PATH], *tmp; - HDEVINFO set, xi_set; - BOOL override; - UINT32 i = 0; - GUID hid; - - TRACE( "index %d, guid %s\n", index, debugstr_guid( guid ) ); - - HidD_GetHidGuid( &hid ); - - set = SetupDiGetClassDevsW( &hid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT ); - if (set == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG; - xi_set = SetupDiGetClassDevsW( &GUID_DEVINTERFACE_WINEXINPUT, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT ); - - *device = NULL; - *preparsed = NULL; - while (SetupDiEnumDeviceInterfaces( set, NULL, &hid, i++, &iface )) - { - detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, &devinfo )) - continue; - if (FAILED(hid_joystick_device_try_open( detail->DevicePath, device, preparsed, - attrs, caps, instance, version ))) - continue; - - if (device_instance_is_disabled( instance->tszInstanceName, &override )) - goto next; - - if (override && SetupDiGetDeviceInstanceIdW( set, &devinfo, device_id, MAX_PATH, NULL ) && - (tmp = wcsstr( device_id, L"&IG_" ))) - { - memcpy( tmp, L"&XI_", sizeof(L"&XI_") - sizeof(WCHAR) ); - if (!SetupDiOpenDeviceInfoW( xi_set, device_id, NULL, 0, &devinfo )) - goto next; - if (!SetupDiEnumDeviceInterfaces( xi_set, &devinfo, &GUID_DEVINTERFACE_WINEXINPUT, 0, &iface )) - goto next; - if (!SetupDiGetDeviceInterfaceDetailW( xi_set, &iface, detail, sizeof(buffer), NULL, &devinfo )) - goto next; - - CloseHandle( *device ); - HidD_FreePreparsedData( *preparsed ); - if (FAILED(hid_joystick_device_try_open( detail->DevicePath, device, preparsed, - attrs, caps, instance, version ))) - continue; - } - - /* enumerate device by GUID */ - if (IsEqualGUID( guid, &instance->guidProduct ) || IsEqualGUID( guid, &instance->guidInstance )) break; - - /* enumerate all devices */ - if (index >= 0 && !index--) break; - - next: - CloseHandle( *device ); - HidD_FreePreparsedData( *preparsed ); - *device = NULL; - *preparsed = NULL; - } - - if (xi_set != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList( xi_set ); - SetupDiDestroyDeviceInfoList( set ); - if (!*device || !*preparsed) return DIERR_DEVICENOTREG; - - lstrcpynW( device_path, detail->DevicePath, MAX_PATH ); - return DI_OK; -} - HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version, int index ) { + DIDEVICEINSTANCEW dev_inst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)}; - PHIDP_PREPARSED_DATA preparsed; - WCHAR device_path[MAX_PATH]; + PHIDP_PREPARSED_DATA preparsed = NULL; + WCHAR device_path[MAX_PATH] = { 0 }; GUID guid = GUID_NULL; HIDP_CAPS caps; HANDLE device; @@ -2125,18 +2104,21 @@ HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *in TRACE( "type %#lx, flags %#lx, instance %p, version %#lx, index %d\n", type, flags, instance, version, index ); - hr = hid_joystick_device_open( index, &guid, instance, device_path, &device, &preparsed, - &attrs, &caps, version ); - if (hr != DI_OK) return hr; - - HidD_FreePreparsedData( preparsed ); - CloseHandle( device ); + if (!hid_joystick_cache_get_instance_from_index( index, device_path, &guid )) return DIERR_DEVICENOTREG; + if (SUCCEEDED(hr = hid_joystick_device_try_open( device_path, &device, &preparsed, + &attrs, &caps, &dev_inst, version ))) + { + *instance = dev_inst; + instance->guidInstance = guid; + TRACE( "found device %s, usage %04x:%04x, product %s, instance %s, name %s\n", debugstr_w(device_path), + instance->wUsagePage, instance->wUsage, debugstr_guid( &instance->guidProduct ), + debugstr_guid( &instance->guidInstance ), debugstr_w(instance->tszInstanceName) ); - TRACE( "found device %s, usage %04x:%04x, product %s, instance %s, name %s\n", debugstr_w(device_path), - instance->wUsagePage, instance->wUsage, debugstr_guid( &instance->guidProduct ), - debugstr_guid( &instance->guidInstance ), debugstr_w(instance->tszInstanceName) ); + HidD_FreePreparsedData( preparsed ); + CloseHandle( device ); + } - return DI_OK; + return hr; } static BOOL init_object_properties( struct dinput_device *device, UINT index, struct hid_value_caps *caps, @@ -2507,8 +2489,19 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi impl->base.read_event = CreateEventW( NULL, TRUE, FALSE, NULL ); if (memcmp( device_path_guid.Data4, guid->Data4, sizeof(device_path_guid.Data4) )) - hr = hid_joystick_device_open( -1, guid, &impl->base.instance, impl->device_path, &impl->device, &impl->preparsed, - &attrs, &impl->caps, dinput->dwVersion ); + { + GUID guid_instance; + + if (hid_joystick_cache_get_instance_from_guid( guid, impl->device_path, &guid_instance )) + { + hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, + &impl->caps, &impl->base.instance, dinput->dwVersion ); + if (SUCCEEDED(hr)) + impl->base.instance.guidInstance = guid_instance; + } + else + hr = DIERR_DEVICENOTREG; + } else { wcscpy( impl->device_path, *(const WCHAR **)guid ); diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 10a3051e8ce..e4147797652 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -222,7 +222,7 @@ static BOOL test_input_lost( DWORD version ) hr = dinput_test_create_device( version, &devinst2, &device2 ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); ok( !!device2, "device2 is NULL.\n" ); - todo_wine ok( !memcmp( &devinst.guidInstance, &devinst2.guidInstance, sizeof(GUID) ), + ok( !memcmp( &devinst.guidInstance, &devinst2.guidInstance, sizeof(GUID) ), "Unexpected guidInstance.\n" ); ref = IDirectInputDevice8_Release( device2 ); ok( ref == 0, "Release returned %ld\n", ref ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 5b2ca8fe66d..ca3f5f12f6a 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -6161,7 +6161,7 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di2, &expect_instances[0], &device ); - if (version == 0x800) todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); + if (version == 0x800) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); else ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); if (SUCCEEDED(hr)) { @@ -6191,13 +6191,12 @@ static void test_joystick_instance_guid( DWORD version ) { winetest_push_context( "device %d", i ); - todo_wine ok( !IsEqualGUID( &expect_instances[i], &instances[i] ), + ok( !IsEqualGUID( &expect_instances[i], &instances[i] ), "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); /* Old guidInstance no longer works. */ hr = dinput_create_device( &di, &expect_instances[i], &device ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); expect_instances[i] = instances[i]; /* New guidInstance, same device. */ @@ -6224,8 +6223,7 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); instances_end = instances; hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end ); @@ -6245,8 +6243,7 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); instances_end = instances; hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end ); @@ -6267,8 +6264,7 @@ static void test_joystick_instance_guid( DWORD version ) IDirectInputDevice8_Release( device ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &instances[1], &device ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); @@ -6293,11 +6289,9 @@ static void test_joystick_instance_guid( DWORD version ) /* Stopped devices should return E_FAIL. */ hr = dinput_create_device( &di, &instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &instances[2], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); /* After calling EnumDevices(), guidInstance values will be reassigned. */ instances_end = instances; @@ -6311,7 +6305,7 @@ static void test_joystick_instance_guid( DWORD version ) winetest_push_context( "device %d", i ); - todo_wine ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), + ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); hr = dinput_create_device( &di, &instances[i], &device ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); @@ -6335,7 +6329,7 @@ static void test_joystick_instance_guid( DWORD version ) winetest_push_context( "device %d", i ); - todo_wine ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), + ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); hr = dinput_create_device( &di, &instances[i], &device ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); @@ -6356,7 +6350,6 @@ static void test_joystick_instance_guid( DWORD version ) { winetest_push_context( "device %d", i ); - todo_wine_if( !(i & 0x1) ) ok( IsEqualGUID( &expect_instances[i], &instances[i] ), "Unexpected guidInstance %s.\n", debugstr_guid( &instances[i] ) ); @@ -6397,17 +6390,13 @@ static void test_joystick_instance_guid( DWORD version ) hid_device_start( &descs[i], 1 ); hr = dinput_create_device( &di, &expect_instances[i], &device ); - todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) - { - check_device_hid_serial( device, descs[i].serial_str ); - IDirectInputDevice8_Release( device ); - } + ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); + check_device_hid_serial( device, descs[i].serial_str ); + IDirectInputDevice8_Release( device ); hid_device_stop( &descs[i], 1 ); hr = dinput_create_device( &di, &expect_instances[i], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); hid_device_start( &descs[i], 1 ); winetest_pop_context(); @@ -6434,17 +6423,13 @@ static void test_joystick_instance_guid( DWORD version ) hid_device_start( &descs[0], 1 ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) - { - check_device_hid_serial( device, descs[0].serial_str ); - IDirectInputDevice8_Release( device ); - } + ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); + check_device_hid_serial( device, descs[0].serial_str ); + IDirectInputDevice8_Release( device ); hid_device_stop( &descs[0], 1 ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); /* Start device 1. */ @@ -6455,8 +6440,7 @@ static void test_joystick_instance_guid( DWORD version ) * with device 0. */ hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); /* * expect_instances[1] is not currently associated with a device, which @@ -6468,12 +6452,9 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) - { - check_device_hid_serial( device, descs[1].serial_str ); - IDirectInputDevice8_Release( device ); - } + ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); + check_device_hid_serial( device, descs[1].serial_str ); + IDirectInputDevice8_Release( device ); hid_device_stop( &descs[1], 1 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10364