When a program calls SetProperty with DIPROP_BUFFERSIZE, dinput records this value for GetProperty but only uses it when the device can support that number of buffers otherwise it ignores this value..
In the case of game "Far Cry 5", it passes through (DWORD)-1 which cause HeapAlloc to fail ((DWORD)-1 * sizeof(DIDEVICEOBJECTDATA)).
Since there is no real way of working out the max value, I've capped it at 100 as the default value is 20.
MSDN reference. https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee417908(...)
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45732
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/dinput/device.c | 14 ++++++++++---- dlls/dinput/device_private.h | 3 ++- dlls/dinput/joystick_linux.c | 4 ++++ dlls/dinput/joystick_linuxinput.c | 4 ++++ dlls/dinput/joystick_osx.c | 4 ++++ dlls/dinput/keyboard.c | 3 +++ dlls/dinput/mouse.c | 3 +++ dlls/dinput/tests/device.c | 14 ++++++++++++++ 8 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 28329d03b5..1604075f84 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1307,7 +1307,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
- pd->dwData = This->queue_len; + pd->dwData = This->buffersize; TRACE("buffersize = %d\n", pd->dwData); break; } @@ -1396,12 +1396,18 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty( TRACE("buffersize = %d\n", pd->dwData);
EnterCriticalSection(&This->crit); + + This->buffersize = pd->dwData; + + This->queue_len = This->buffersize > 100 ? 100 : This->buffersize; + if (This->buffersize > 100) + WARN("Trying to set large buffer size %d\n", pd->dwData); + HeapFree(GetProcessHeap(), 0, This->data_queue);
- This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0, - pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->data_queue = !This->queue_len ? NULL : HeapAlloc(GetProcessHeap(), 0, + This->queue_len * sizeof(DIDEVICEOBJECTDATA)); This->queue_head = This->queue_tail = This->overflow = 0; - This->queue_len = pd->dwData;
LeaveCriticalSection(&This->crit); break; diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index 27e9c26286..23d9e2eebc 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -71,10 +71,11 @@ struct IDirectInputDeviceImpl DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */
LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ - int queue_len; /* size of the queue - set in 'SetProperty' */ + int queue_len; /* valid size of the queue */ int queue_head; /* position to write new event into queue */ int queue_tail; /* next event to read from queue */ BOOL overflow; /* return DI_BUFFEROVERFLOW in 'GetDeviceData' */ + DWORD buffersize; /* size of the queue - set in 'SetProperty' */
DataFormat data_format; /* user data format and wine to user format converter */
diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c index afdf659b4a..1e7bf72936 100644 --- a/dlls/dinput/joystick_linux.c +++ b/dlls/dinput/joystick_linux.c @@ -501,6 +501,10 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput, newDevice->generic.base.ref = 1; newDevice->generic.base.dinput = dinput; newDevice->generic.base.guid = *rguid; + newDevice->generic.base.buffersize = 20; + newDevice->generic.base.queue_len = 20; + newDevice->generic.base.data_queue = HeapAlloc(GetProcessHeap(), 0, + newDevice->generic.base.queue_len * sizeof(DIDEVICEOBJECTDATA)); InitializeCriticalSection(&newDevice->generic.base.crit); newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c index b5418d805c..98283a1eed 100644 --- a/dlls/dinput/joystick_linuxinput.c +++ b/dlls/dinput/joystick_linuxinput.c @@ -471,6 +471,10 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig newDevice->generic.base.ref = 1; newDevice->generic.base.guid = *rguid; newDevice->generic.base.dinput = dinput; + newDevice->generic.base.buffersize = 20; + newDevice->generic.base.queue_len = 20; + newDevice->generic.base.data_queue = HeapAlloc(GetProcessHeap(), 0, + newDevice->generic.base.queue_len * sizeof(DIDEVICEOBJECTDATA)); newDevice->generic.joy_polldev = joy_polldev; newDevice->joyfd = -1; newDevice->joydev = &joydevs[index]; diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c index 990f5d1f07..c48cad1f5a 100644 --- a/dlls/dinput/joystick_osx.c +++ b/dlls/dinput/joystick_osx.c @@ -1168,6 +1168,10 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput, newDevice->generic.base.ref = 1; newDevice->generic.base.dinput = dinput; newDevice->generic.base.guid = *rguid; + newDevice->generic.base.buffersize = 20; + newDevice->generic.base.queue_len = 20; + newDevice->generic.base.data_queue = HeapAlloc(GetProcessHeap(), 0, + newDevice->generic.base.queue_len * sizeof(DIDEVICEOBJECTDATA)); InitializeCriticalSection(&newDevice->generic.base.crit); newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index 47f28cac52..15a6be4dee 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -268,6 +268,9 @@ static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) InitializeCriticalSection(&newDevice->base.crit); newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit"); newDevice->subtype = get_keyboard_subtype(); + newDevice->base.buffersize = 20; + newDevice->base.queue_len = 20; + newDevice->base.data_queue = HeapAlloc(GetProcessHeap(), 0, newDevice->base.queue_len * sizeof(DIDEVICEOBJECTDATA));
/* Create copy of default data format */ if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard.dwSize))) goto failed; diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 08ace2f4e9..59c8c9dad8 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -214,6 +214,9 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit"); newDevice->base.dinput = dinput; newDevice->base.event_proc = dinput_mouse_hook; + newDevice->base.buffersize = 20; + newDevice->base.queue_len = 20; + newDevice->base.data_queue = HeapAlloc(GetProcessHeap(), 0, newDevice->base.queue_len * sizeof(DIDEVICEOBJECTDATA));
get_app_key(&hkey, &appkey); if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer))) diff --git a/dlls/dinput/tests/device.c b/dlls/dinput/tests/device.c index a2a5a65686..4dd16c70d2 100644 --- a/dlls/dinput/tests/device.c +++ b/dlls/dinput/tests/device.c @@ -106,8 +106,22 @@ static void test_object_info(IDirectInputDeviceA *device, HWND hwnd) dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); dp.diph.dwHow = DIPH_DEVICE; dp.diph.dwObj = 0; + dp.dwData = -1; + + hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph); + ok(hr == DI_OK, "Failed: %08x\n", hr); + ok(dp.dwData == 20, "got %d\n", dp.dwData); + + dp.dwData = -1; + hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph); + ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); + dp.dwData = 0; + hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph); + ok(hr == DI_OK, "Failed: %08x\n", hr); + ok(dp.dwData == -1, "got %d\n", dp.dwData);
+ dp.dwData = 0; hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph); ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); cnt = 5;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=63131
Your paranoid android.
=== wxppro (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w2003std (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== wvistau64 (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w2008s64 (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w7u (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w8 (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w8adm (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w864 (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1507 (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809 (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809_2scr (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809_ar (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809_he (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809_ja (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809_zh_CN (32 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== wvistau64 (64 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w2008s64 (64 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w864 (64 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1507 (64 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== w1064v1809 (64 bit report) ===
dinput: device.c:113: Test failed: got 0 device.c:113: Test failed: got 0
=== debian10 (64 bit WoW report) ===
dinput: mouse.c:152: Test failed: Failed: 00000001 mouse.c:158: Test failed: Failed: 80070005 mouse.c:161: Test failed: Failed: 00000001 mouse.c:164: Test failed: Failed: 80070005 mouse.c:178: Test failed: GetDeviceData() failed: 00000000 cnt:0