From: Vibhav Pant vibhavp@gmail.com
--- dlls/dinput/tests/Makefile.in | 2 +- dlls/dinput/tests/hotplug.c | 203 +++++++++++++++++++++++++++++++++- 2 files changed, 203 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index 608b817e0f4..c40300e619b 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dinput.dll -IMPORTS = dinput dinput8 ole32 version user32 advapi32 hid uuid crypt32 newdev setupapi wintrust winmm +IMPORTS = dinput dinput8 ole32 version user32 advapi32 hid uuid crypt32 newdev setupapi wintrust winmm cfgmgr32
driver_bus_IMPORTS = winecrt0 ntoskrnl hal driver_bus_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index f7199d2b17e..0c068d04b04 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -34,6 +34,7 @@ #include "dbt.h" #include "unknwn.h" #include "winstring.h" +#include "cfgmgr32.h"
#include "wine/hid.h"
@@ -279,6 +280,7 @@ static const union device_change_event static const union device_change_event *device_change_expect_event; static HANDLE device_change_expect_handle; static HDEVNOTIFY handle_devnotify; +static HCMNOTIFICATION handle_cmnotify;
static LRESULT CALLBACK devnotify_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { @@ -365,6 +367,110 @@ static LRESULT CALLBACK devnotify_wndproc( HWND hwnd, UINT msg, WPARAM wparam, L return DefWindowProcW( hwnd, msg, wparam, lparam ); }
+struct cm_notify_callback_data +{ + HCMNOTIFICATION hnotify; + DWORD device_change_expect; + DWORD device_change_expect_custom; + BOOL device_change_all; + + DWORD device_change_count; + HANDLE device_change_sem; + + BOOL received_deviceremovalcomplete; +}; + +static CALLBACK DWORD cm_notify_callback( HCMNOTIFICATION hnotify, void *ctx, CM_NOTIFY_ACTION action, + CM_NOTIFY_EVENT_DATA *data, DWORD size ) +{ + struct cm_notify_callback_data *cb_data = ctx; + + switch (action) + { + case CM_NOTIFY_ACTION_DEVICECUSTOMEVENT: + { + const union device_change_event *event; + SIZE_T idx; + + ok( hnotify == handle_cmnotify, "%p != %p\n", hnotify, handle_cmnotify ); + ok( !!cb_data->device_change_expect_custom, "unexpected event\n" ); + idx = (ARRAY_SIZE(device_change_events) + 1) - cb_data->device_change_expect_custom; + event = &device_change_events[idx]; + + winetest_push_context( "%Id", idx ); + ok( size == offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceHandle.Data[data->u.DeviceHandle.DataSize] ), + "got %#lx\n", size ); + ok( IsEqualGUID( &data->u.DeviceHandle.EventGuid, &event->Event ), "got DeviceHandle.EventGuid %s\n", + debugstr_guid( &data->u.DeviceHandle.EventGuid ) ); + ok( data->u.DeviceHandle.NameOffset == event->NameBufferOffset, "got DeviceHandle.NameOffset %ld\n", + data->u.DeviceHandle.NameOffset ); + ok( data->u.DeviceHandle.DataSize == event->Size - offsetof( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer[0] ), + "got DeviceHandle.DataSize %ld\n", data->u.DeviceHandle.DataSize ); + ok( !memcmp( data->u.DeviceHandle.Data, event->CustomDataBuffer, data->u.DeviceHandle.DataSize ), + "Unexpected DeviceHandle.Data\n" ); + winetest_pop_context(); + + cb_data->device_change_expect_custom--; + cb_data->device_change_count++; + ReleaseSemaphore( cb_data->device_change_sem, 1, NULL ); + break; + } + case CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE: + ok( size == sizeof(*data), "got %#lx\n", size ); + ok( cb_data->device_change_expect_custom, "Unexpected CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE\n" ); + cb_data->received_deviceremovalcomplete = TRUE; + cb_data->device_change_count++; + ReleaseSemaphore( cb_data->device_change_sem, 1, NULL ); + break; + case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL: + case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL: + { + const WCHAR *expect_prefix, *name = data->u.DeviceInterface.SymbolicLink, *upper_end, *name_end; + GUID expect_guid; + + ok( hnotify == cb_data->hnotify, "%p != %p\n", hnotify, cb_data->hnotify ); + ok( size == offsetof( CM_NOTIFY_EVENT_DATA, u.DeviceInterface.SymbolicLink[wcslen( name ) + 1] ), "got %#lx\n", size ); + if (cb_data->device_change_all && (!cb_data->device_change_count || cb_data->device_change_count == 3)) + { + expect_guid = control_class; + expect_prefix = L"\\?\WINETEST#"; + } + else + { + expect_guid = GUID_DEVINTERFACE_HID; + expect_prefix = L"\\?\HID#"; + } + + winetest_push_context( "%lu", cb_data->device_change_count ); + ok( IsEqualGUID( &data->u.DeviceInterface.ClassGuid, &expect_guid ), "got u.DeviceInterface.ClassGuid %s\n", + debugstr_guid( &data->u.DeviceInterface.ClassGuid ) ); + ok( !wcsncmp( name, expect_prefix, wcslen( expect_prefix ) ), "got u.DeviceInterface.SymbolicLink %s\n", + debugstr_w( name ) ); + upper_end = wcschr( name + wcslen( expect_prefix ), '#' ); + name_end = name + wcslen( name ) + 1; + ok( !!upper_end, "got u.DeviceInterface.SymbolicLink %s\n", debugstr_w( name ) ); + ok( all_upper( name, upper_end ), "got u.DeviceInterface.SymbolicLink %s\n", debugstr_w( name ) ); + ok( all_lower( upper_end, name_end ), "got u.DeviceInterface.SymbolicLink %s\n", debugstr_w( name ) ); + + if (cb_data->device_change_count++ >= cb_data->device_change_expect / 2) + ok( action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL, "got action %d\n", action ); + else if (cb_data->device_change_expect_custom) + ok( action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL, "got action %d\n", action ); + else + ok( action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL, "got action %d\n", action ); + + winetest_pop_context(); + ReleaseSemaphore( cb_data->device_change_sem, 1, NULL ); + break; + } + default: + ok( 0, "Unexpected CM_NOTIFY_ACTION %d\n", action ); + break; + } + + return ERROR_SUCCESS; +} + static void test_RegisterDeviceNotification(void) { DEV_BROADCAST_DEVICEINTERFACE_A iface_filter_a = @@ -385,11 +491,32 @@ static void test_RegisterDeviceNotification(void) .lpszClassName = L"devnotify", .lpfnWndProc = devnotify_wndproc, }; + CM_NOTIFY_FILTER cm_iface_filter = + {.cbSize = sizeof(CM_NOTIFY_FILTER), + .Flags = 0, + .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE, + .Reserved = 0, + .u = {.DeviceInterface = {.ClassGuid = GUID_DEVINTERFACE_HID}}}; + CM_NOTIFY_FILTER cm_all_ifaces_filter = + { + .cbSize = sizeof(CM_NOTIFY_FILTER), + .Flags = CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES, + .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE, + .Reserved = 0, + }; + CM_NOTIFY_FILTER cm_handle_filter = + { + .cbSize = sizeof(CM_NOTIFY_FILTER), + .Flags = 0, + .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE, + .Reserved = 0, + }; char buffer[1024] = {0}; DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *)buffer; + struct cm_notify_callback_data cm_ctx = {0}; HANDLE hwnd, thread, stop_event; HDEVNOTIFY devnotify; - DWORD ret; + DWORD i, ret; MSG msg;
RegisterClassExW( &class ); @@ -461,6 +588,16 @@ static void test_RegisterDeviceNotification(void) ok( !!devnotify, "RegisterDeviceNotificationA failed, error %lu\n", GetLastError() ); while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
+ cm_ctx.device_change_sem = CreateSemaphoreW( NULL, 0, 2 + ARRAY_SIZE(device_change_events), NULL ); + ok( !!cm_ctx.device_change_sem, "CreateSemaphoreW failed, error %lu\n", GetLastError() ); + + cm_ctx.device_change_all = FALSE; + cm_ctx.device_change_expect = 2; + cm_ctx.device_change_count = 0; + + ret = CM_Register_Notification( &cm_iface_filter, &cm_ctx, cm_notify_callback, &cm_ctx.hnotify ); + todo_wine ok( !ret, "CM_Register_Notification failed, error %lu\n", ret ); + device_change_count = 0; device_change_expect = 2; device_change_hwnd = hwnd; @@ -483,6 +620,13 @@ static void test_RegisterDeviceNotification(void) } if (device_change_count == device_change_expect / 2) SetEvent( stop_event ); } + for (i = 0; i < cm_ctx.device_change_expect; i++) + { + ret = WaitForSingleObject( cm_ctx.device_change_sem, 100 ); + todo_wine ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + } + todo_wine ok( cm_ctx.device_change_count == cm_ctx.device_change_expect, "%lu != %lu\n", + cm_ctx.device_change_count, cm_ctx.device_change_expect );
ret = WaitForSingleObject( thread, 5000 ); ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); @@ -490,6 +634,7 @@ static void test_RegisterDeviceNotification(void) CloseHandle( stop_event );
UnregisterDeviceNotification( devnotify ); + CM_Unregister_Notification( cm_ctx.hnotify );
memcpy( buffer, &iface_filter_a, sizeof(iface_filter_a) ); strcpy( ((DEV_BROADCAST_DEVICEINTERFACE_A *)buffer)->dbcc_name, "device name" ); @@ -498,6 +643,13 @@ static void test_RegisterDeviceNotification(void) ok( !!devnotify, "RegisterDeviceNotificationA failed, error %lu\n", GetLastError() ); while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
+ cm_ctx.device_change_all = FALSE; + cm_ctx.device_change_expect = 2; + cm_ctx.device_change_count = 0; + + ret = CM_Register_Notification( &cm_iface_filter, &cm_ctx, cm_notify_callback, &cm_ctx.hnotify ); + todo_wine ok( !ret, "CM_Register_Notification failed, error %lu\n", ret ); + device_change_count = 0; device_change_expect = 2; device_change_hwnd = hwnd; @@ -520,6 +672,13 @@ static void test_RegisterDeviceNotification(void) } if (device_change_count == device_change_expect / 2) SetEvent( stop_event ); } + for (i = 0; i < cm_ctx.device_change_expect; i++) + { + ret = WaitForSingleObject( cm_ctx.device_change_sem, 100 ); + todo_wine ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + } + todo_wine ok( cm_ctx.device_change_count == cm_ctx.device_change_expect, "%lu != %lu\n", + cm_ctx.device_change_count, cm_ctx.device_change_expect );
ret = WaitForSingleObject( thread, 5000 ); ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); @@ -527,11 +686,19 @@ static void test_RegisterDeviceNotification(void) CloseHandle( stop_event );
UnregisterDeviceNotification( devnotify ); + CM_Unregister_Notification( cm_ctx.hnotify );
devnotify = RegisterDeviceNotificationA( hwnd, &iface_filter_a, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES ); ok( !!devnotify, "RegisterDeviceNotificationA failed, error %lu\n", GetLastError() ); while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
+ cm_ctx.device_change_all = TRUE; + cm_ctx.device_change_expect = 4; + cm_ctx.device_change_count = 0; + ret = CM_Register_Notification( &cm_all_ifaces_filter, &cm_ctx, cm_notify_callback, + &cm_ctx.hnotify ); + todo_wine ok( !ret, "CM_Register_Notification failed, error %lu\n", ret ); + device_change_count = 0; device_change_expect = 4; device_change_hwnd = hwnd; @@ -554,6 +721,13 @@ static void test_RegisterDeviceNotification(void) } if (device_change_count == device_change_expect / 2) SetEvent( stop_event ); } + for (i = 0; i < cm_ctx.device_change_expect; i++) + { + ret = WaitForSingleObject( cm_ctx.device_change_sem, 100 ); + todo_wine ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + } + todo_wine ok( cm_ctx.device_change_count == cm_ctx.device_change_expect, "%lu != %lu\n", + cm_ctx.device_change_count, cm_ctx.device_change_expect );
ret = WaitForSingleObject( thread, 5000 ); ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); @@ -561,11 +735,19 @@ static void test_RegisterDeviceNotification(void) CloseHandle( stop_event );
UnregisterDeviceNotification( devnotify ); + CM_Unregister_Notification( cm_ctx.hnotify );
devnotify = RegisterDeviceNotificationA( hwnd, &iface_filter_a, DEVICE_NOTIFY_WINDOW_HANDLE ); ok( !!devnotify, "RegisterDeviceNotificationA failed, error %lu\n", GetLastError() ); while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
+ cm_ctx.device_change_all = FALSE; + cm_ctx.device_change_expect = 2 + ARRAY_SIZE(device_change_events); + cm_ctx.device_change_count = 0; + cm_iface_filter.Flags = 0; + ret = CM_Register_Notification( &cm_iface_filter, &cm_ctx, cm_notify_callback, &cm_ctx.hnotify ); + todo_wine ok( !ret, "CM_Register_Notification failed, error %lu\n", ret ); + device_change_count = 0; device_change_expect = 2; device_change_hwnd = hwnd; @@ -592,6 +774,9 @@ static void test_RegisterDeviceNotification(void) HANDLE file; UINT i;
+ ret = WaitForSingleObject( cm_ctx.device_change_sem, 100 ); + todo_wine ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + swprintf( device_path, MAX_PATH, L"\\?\hid#vid_%04x&pid_%04x", LOWORD(EXPECT_VIDPID), HIWORD(EXPECT_VIDPID) ); ret = find_hid_device_path( device_path ); ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) ); @@ -604,8 +789,13 @@ static void test_RegisterDeviceNotification(void) handle_devnotify = RegisterDeviceNotificationA( hwnd, &handle_filter_a, DEVICE_NOTIFY_WINDOW_HANDLE ); ok( !!handle_devnotify, "RegisterDeviceNotificationA failed, error %lu\n", GetLastError() );
+ cm_handle_filter.u.DeviceHandle.hTarget = file; + ret = CM_Register_Notification( &cm_handle_filter, &cm_ctx, cm_notify_callback, &handle_cmnotify ); + todo_wine ok( !ret, "CM_Register_Notification failed, error %lu\n", ret ); + device_change_expect_handle = file; device_change_expect_event = device_change_events; + cm_ctx.device_change_expect_custom = ARRAY_SIZE(device_change_events) + 1; for (i = 0; i < ARRAY_SIZE(device_change_events) - 1; i++) { ret = sync_ioctl( file, IOCTL_WINETEST_DEVICE_CHANGE, (BYTE *)&device_change_events[i].notif, @@ -619,6 +809,14 @@ static void test_RegisterDeviceNotification(void) } if (device_change_count == 1 && device_change_expect_custom == 1) SetEvent( stop_event ); } + for (i = 1; i < cm_ctx.device_change_expect; i++) + { + ret = WaitForSingleObject( cm_ctx.device_change_sem, 100 ); + todo_wine ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + } + todo_wine ok( cm_ctx.device_change_count == cm_ctx.device_change_expect, "%lu != %lu\n", + cm_ctx.device_change_count, cm_ctx.device_change_expect ); + todo_wine ok( cm_ctx.received_deviceremovalcomplete, "%d != 0\n", cm_ctx.received_deviceremovalcomplete );
ret = WaitForSingleObject( thread, 5000 ); ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); @@ -626,9 +824,12 @@ static void test_RegisterDeviceNotification(void) CloseHandle( stop_event );
if (handle_devnotify) UnregisterDeviceNotification( handle_devnotify ); + if (handle_cmnotify) CM_Unregister_Notification( handle_cmnotify ); UnregisterDeviceNotification( devnotify ); + CM_Unregister_Notification( cm_ctx.hnotify ); device_change_expect_event = NULL; handle_devnotify = 0; + CloseHandle( cm_ctx.device_change_sem );
DestroyWindow( hwnd ); UnregisterClassW( class.lpszClassName, class.hInstance );