From: Vibhav Pant vibhavp@gmail.com
--- dlls/sechost/service.c | 19 +++++++++- dlls/user32/input.c | 77 ++++++++++++++++++++++++++++++++++++++- include/wine/dbt.h | 6 +++ include/wine/plugplay.idl | 11 ++++++ programs/plugplay/main.c | 48 +++++++++++++++++++++++- 5 files changed, 158 insertions(+), 3 deletions(-)
diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c index 0377123694e..56dccd0bfca 100644 --- a/dlls/sechost/service.c +++ b/dlls/sechost/service.c @@ -1997,6 +1997,9 @@ debugstr_device_notification_details( const struct device_notification_details * return wine_dbg_sprintf( "{%p %p DBT_DEVTYP_DEVICEINTERFACE {class=%s}}", details->cb, details->handle, debugstr_guid( &details->filter.deviceinterface.class ) ); + case DBT_DEVTYP_HANDLE: + return wine_dbg_sprintf( "{%p %p DBT_DEVTYP_HANDLE {%p %p}}", details->cb, details->handle, + details->filter.device.name_info, details->filter.device.device ); default: return wine_dbg_sprintf( "{%p %p (unknown %#lx)}", details->cb, details->handle, details->devicetype); } @@ -2013,6 +2016,11 @@ static BOOL notification_filter_matches( struct device_notification_details *det if (details->filter.deviceinterface.all_classes) return TRUE; return IsEqualGUID( &details->filter.deviceinterface.class, &data->event.device_interface.class_guid ); } + else if (details->devicetype == DBT_DEVTYP_HANDLE) + { + return wcsicmp( details->filter.device.name_info->Name.Buffer, + data->event.handle.handle_file_path ); + } FIXME( "unknown filter devicetype value %#lx\n", details->devicetype ); return TRUE; } @@ -2112,7 +2120,7 @@ static DWORD WINAPI device_notify_proc( void *arg ) for (i = 0; i < details_copy_nelems; i++) { struct device_notification_details *details = &details_copy[i].details; - HANDLE device = NULL; + HANDLE device = code == DBT_DEVTYP_HANDLE ? details->filter.device.device : NULL;
if (!notification_filter_matches( details, &broadcast_data )) continue; TRACE( "dispatching %s, matched by filter %s\n", @@ -2125,6 +2133,13 @@ static DWORD WINAPI device_notify_proc( void *arg ) case DBT_DEVTYP_DEVICEINTERFACE: str = broadcast_data.event.device_interface.name; break; + case DBT_DEVTYP_HANDLE: + str = broadcast_data.event.handle.name; + MIDL_user_free( broadcast_data.event.handle.handle_file_path ); + if (broadcast_data.event.handle.name) + MIDL_user_free( broadcast_data.event.handle.name ); + if (broadcast_data.event.handle.data_size != 0) + MIDL_user_free( broadcast_data.event.handle.data ); } if (str) MIDL_user_free( str ); } @@ -2188,6 +2203,8 @@ BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle ) EnterCriticalSection( &service_cs ); list_remove( ®istration->entry ); LeaveCriticalSection(&service_cs); + if (registration->details.devicetype == DBT_DEVTYP_HANDLE) + free( registration->details.filter.device.name_info ); free( registration ); return TRUE; } diff --git a/dlls/user32/input.c b/dlls/user32/input.c index a204521c7b0..534eb3eceb4 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -527,6 +527,29 @@ static DWORD CALLBACK devnotify_window_callbackW( HANDLE handle, HDEVNOTIFY noti free( iface ); break; } + case DBT_DEVTYP_HANDLE: + { + DEV_BROADCAST_HANDLE *bc_handle; + DWORD data_size = data->event.handle.data_size; + DWORD name_size = data->event.handle.name ? wcslen( data->event.handle.name ) + 1 : 0; + DWORD dbch_size = offsetof( DEV_BROADCAST_HANDLE, + dbch_data[name_size + data_size] ); + bc_handle = calloc( 1, dbch_size ); + if (!bc_handle) + return 0; + bc_handle->dbch_size = dbch_size; + bc_handle->dbch_devicetype = DBT_DEVTYP_HANDLE; + bc_handle->dbch_handle = device_handle; + bc_handle->dbch_hdevnotify = notify; + bc_handle->dbch_eventguid = data->event.handle.event_guid; + bc_handle->dbch_nameoffset = name_size ? data_size : -1; + memcpy( bc_handle->dbch_data, data->event.handle.data, data_size ); + memcpy( &bc_handle->dbch_data[data_size], data->event.handle.name, name_size ); + SendMessageTimeoutW( handle, WM_DEVICECHANGE, flags, (LPARAM)bc_handle, SMTO_ABORTIFHUNG, + 2000, NULL ); + free( bc_handle ); + break; + } default: FIXME("unimplemented devicetype %#lx\n", data->devicetype); break; @@ -562,6 +585,34 @@ static DWORD CALLBACK devnotify_window_callbackA( HANDLE handle, HDEVNOTIFY noti free( ifaceA ); break; } + + case DBT_DEVTYP_HANDLE: + { + DEV_BROADCAST_HANDLE *bc_handle; + size_t lenW = data->event.handle.name ? wcslen( data->event.handle.name ) + 1: 0; + DWORD data_size = data->event.handle.data_size; + DWORD lenA = 0; + + bc_handle = calloc( 1, offsetof( DEV_BROADCAST_HANDLE, dbch_data[lenW * 3 + 1 + data_size] ) ); + if (!bc_handle) + return 0; + + if (lenW) + lenA = WideCharToMultiByte( CP_ACP, 0, data->event.handle.name, lenW + 1, + (char *)&bc_handle->dbch_data[data_size], lenW * 3 + 1, + NULL, NULL ); + bc_handle->dbch_nameoffset = lenW ? data_size : -1; + bc_handle->dbch_size = offsetof( DEV_BROADCAST_HANDLE, dbch_data[lenA + 1] ); + bc_handle->dbch_devicetype = DBT_DEVTYP_HANDLE; + bc_handle->dbch_handle = device_handle; + bc_handle->dbch_hdevnotify = notify; + bc_handle->dbch_eventguid = data->event.handle.event_guid; + memcpy( bc_handle->dbch_data, data->event.handle.data, data_size ); + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)bc_handle, + SMTO_ABORTIFHUNG, 200, NULL ); + free( bc_handle ); + break; + } default: FIXME( "unimplemented W to A mapping for %#lx\n", data->devicetype ); break; @@ -622,7 +673,31 @@ HDEVNOTIFY WINAPI RegisterDeviceNotificationW( HANDLE handle, void *filter, DWOR details.filter.deviceinterface.class = iface->dbcc_classguid; } else if (header->dbch_devicetype == DBT_DEVTYP_HANDLE) - FIXME( "DBT_DEVTYP_HANDLE filter type not implemented\n" ); + { + OBJECT_NAME_INFORMATION *name_info; + DEV_BROADCAST_HANDLE *handle = (DEV_BROADCAST_HANDLE *)header; + HANDLE device = handle->dbch_handle; + NTSTATUS status; + DWORD size; + + details.devicetype = DBT_DEVTYP_HANDLE; + status = NtQueryObject( device, ObjectNameInformation, NULL, 0, &size ); + if (status != STATUS_INFO_LENGTH_MISMATCH) + { + SetLastError( RtlNtStatusToDosError( status ) ); + return NULL; + } + + name_info = malloc( size ); + if (!name_info) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return NULL; + } + + details.filter.device.device = device; + details.filter.device.name_info = name_info; + } else { SetLastError( ERROR_INVALID_DATA ); diff --git a/include/wine/dbt.h b/include/wine/dbt.h index 37e5506ef20..d059ce94c01 100644 --- a/include/wine/dbt.h +++ b/include/wine/dbt.h @@ -62,6 +62,12 @@ static inline const char *debugstr_device_broadcast(const struct device_broadcas return wine_dbg_sprintf( "{DBT_DEVTYP_DEVICEINTERFACE %s %s}", debugstr_guid( &data->event.device_interface.class_guid ), debugstr_w( data->event.device_interface.name ) ); + case DBT_DEVTYP_HANDLE: + return wine_dbg_sprintf( "{DBT_DEVTYP_HANDLE %s %s %s %lu %p}", + debugstr_w( data->event.handle.handle_file_path ), + debugstr_guid( &data->event.handle.event_guid ), + debugstr_w( data->event.handle.name ), + data->event.handle.data_size, data->event.handle.data ); default: return wine_dbg_sprintf( "{type=%#lx %p}\n", data->devicetype, data ); } diff --git a/include/wine/plugplay.idl b/include/wine/plugplay.idl index e514570e5c4..47a95240c7d 100644 --- a/include/wine/plugplay.idl +++ b/include/wine/plugplay.idl @@ -27,10 +27,21 @@ struct device_broadcast_deviceinterface [string] LPWSTR name; };
+struct device_broadcast_handle +{ + LPWSTR handle_file_path; + GUID event_guid; + [string] LPWSTR name; + DWORD data_size; + [unique, size_is(data_size)] BYTE *data; +}; + union device_broadcast switch (DWORD devicetype) event { /* DBT_DEVTYP_DEVICEINTERFACE */ case 5: struct device_broadcast_deviceinterface device_interface; + /* BROADCAST_DEVICE_TYPE_HANDLE */ + case 6: struct device_broadcast_handle handle; };
[ diff --git a/programs/plugplay/main.c b/programs/plugplay/main.c index c84b967c284..076536374ce 100644 --- a/programs/plugplay/main.c +++ b/programs/plugplay/main.c @@ -85,6 +85,11 @@ static void listener_free_events( struct list *events ) { switch (event->data.devicetype) { + case DBT_DEVTYP_HANDLE: + MIDL_user_free( event->data.event.handle.name ); + MIDL_user_free( event->data.event.handle.handle_file_path ); + MIDL_user_free( event->data.event.handle.data ); + break; case DBT_DEVTYP_DEVICEINTERFACE: MIDL_user_free( event->data.event.device_interface.name ); break; @@ -227,6 +232,47 @@ static struct event *new_event( DWORD event_code, const struct device_broadcast memcpy( name, event_iface->name, name_size ); event->data.event.device_interface.name = name; } + else + { + const struct device_broadcast_handle *event_handle = &src->event.handle; + SIZE_T path_size = sizeof(WCHAR) * (wcslen( event_handle->handle_file_path ) + 1); + WCHAR *path = malloc( path_size ); + + if (!path) + { + free( event ); + return NULL; + } + memcpy( path, event_handle->handle_file_path, path_size ); + event->data.event.handle.handle_file_path = path; + + if (event_handle->data_size != 0) + { + void *data = malloc( event_handle->data_size ); + if (!data) + { + free( path ); + free( event ); + return NULL; + } + memcpy( data, event_handle->data, event_handle->data_size ); + event->data.event.handle.data = data; + } + if (event_handle->name) + { + SIZE_T name_size = (wcslen( event_handle->name ) + 1) * sizeof(WCHAR); + WCHAR *name = malloc( name_size ); + if (!name) + { + free( path ); + if (event_handle->data_size != 0) free( event->data.event.handle.data ); + free( event ); + return NULL; + } + memcpy( name, event_handle->name, name_size ); + event->data.event.handle.name = name; + } + }
return event; } @@ -237,7 +283,7 @@ void __cdecl plugplay_send_event( DWORD code, const struct device_broadcast *dat
TRACE( "(%#lx, %s)\n", code, debugstr_device_broadcast( data ) );
- if (data->devicetype != DBT_DEVTYP_DEVICEINTERFACE) + if (data->devicetype != DBT_DEVTYP_HANDLE && data->devicetype != DBT_DEVTYP_DEVICEINTERFACE) { ERR( "unknown devicetype value: %#lx\n", data->devicetype ); return;