Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Resending the patches. After investigation it looks like the test timeouts are happening randomly, because installing/uninstalling the test driver takes some random amount of time, and fixing them properly will require some unclear amount of work. For now it seems alright, and tests could be split if they start timing out too much, like here.
What is taking the most time are the UpdateDriverForPlugAndPlayDevicesW calls. That can be improved, by installing the test driver only once, and then only creating / destroying the root device, but as far as I could see, this then causes more spurious failures. Probably the device removal is asynchronous, and adding it back quickly is making things worse.
The proper fix, imho, and what I would like to have ultimately anyway for testing multiple devices or hotplug, would be to introduce a bus test device, installed on test startup, and use it to create and remove HID devices, without having to reinstall their drivers. This will require a substantial amount of redesign of the HID test driver, or be done separately and then the other tests switch to it when it's ready.
dlls/dinput/tests/Makefile.in | 1 + dlls/dinput/tests/hotplug.c | 175 ++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 dlls/dinput/tests/hotplug.c
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index b6648008115..44ea9d340bb 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -13,6 +13,7 @@ SOURCES = \ driver_hid.spec \ force_feedback.c \ hid.c \ + hotplug.c \ joystick.c \ joystick8.c \ keyboard.c \ diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c new file mode 100644 index 00000000000..e42af12e810 --- /dev/null +++ b/dlls/dinput/tests/hotplug.c @@ -0,0 +1,175 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define DIRECTINPUT_VERSION 0x0800 + +#include <stdarg.h> +#include <stddef.h> +#include <limits.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" + +#define COBJMACROS +#include "dinput.h" +#include "dinputd.h" +#include "devguid.h" +#include "mmsystem.h" + +#include "wine/hid.h" + +#include "dinput_test.h" + +static BOOL test_input_lost( DWORD version ) +{ +#include "psh_hid_macros.h" + static const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Physical), + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 1, + }; + static const DIPROPDWORD buffer_size = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPDWORD), + .dwHow = DIPH_DEVICE, + .dwObj = 0, + }, + .dwData = UINT_MAX, + }; + + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + DIDEVICEOBJECTDATA objdata[32] = {{0}}; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + IDirectInputDevice8W *device = NULL; + ULONG ref, count, size; + DIJOYSTATE2 state; + HRESULT hr; + + winetest_push_context( "%#x", version ); + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done; + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, 0, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND ); + ok( hr == DI_OK, "SetCooperativeLevel returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &buffer_size.diph ); + ok( hr == DI_OK, "SetProperty returned %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + ok( hr == DI_OK, "GetDeviceState returned %#x\n", hr ); + size = version < 0x0800 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA); + count = 1; + hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( count == 0, "got %u expected %u\n", count, 0 ); + + pnp_driver_stop(); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + todo_wine + ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + todo_wine + ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); + todo_wine + ok( hr == DIERR_INPUTLOST, "GetDeviceData returned %#x\n", hr ); + hr = IDirectInputDevice8_Poll( device ); + todo_wine + ok( hr == DIERR_INPUTLOST, "Poll returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + todo_wine + ok( hr == DIERR_UNPLUGGED, "Acquire returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceData returned %#x\n", hr ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_NOEFFECT, "Unacquire returned: %#x\n", hr ); + + dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 ); + + hr = IDirectInputDevice8_Acquire( device ); + todo_wine + ok( hr == DIERR_UNPLUGGED, "Acquire returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + todo_wine + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#x\n", hr ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + + winetest_pop_context(); + return device != NULL; +} + +START_TEST( hotplug ) +{ + if (!dinput_test_init()) return; + + CoInitialize( NULL ); + if (test_input_lost( 0x500 )) + { + test_input_lost( 0x700 ); + test_input_lost( 0x800 ); + } + CoUninitialize(); + + dinput_test_exit(); +}