From: Vibhav Pant vibhavp@gmail.com
DBT_DEVTYP_HANDLE notifications are registered by providing the file path for the user-provided handle in device_notification_details. The device path is sent with dbch_reserved set to an offset in dbch_data pointing to the path for the device the notification originates from. --- dlls/sechost/service.c | 21 ++++++++++- dlls/user32/input.c | 75 ++++++++++++++++++++++++++++++++++++++-- include/wine/dbt.h | 8 +++++ programs/plugplay/main.c | 8 +++-- 4 files changed, 106 insertions(+), 6 deletions(-)
diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c index 201b4947d4d..c5901d7e3e5 100644 --- a/dlls/sechost/service.c +++ b/dlls/sechost/service.c @@ -31,6 +31,7 @@
#include "wine/debug.h" #include "wine/exception.h" +#include "wine/heap.h" #include "wine/list.h"
#include "svcctl.h" @@ -1998,6 +1999,13 @@ static BOOL notification_filter_matches( const struct device_notification_detail return IsEqualGUID( &filter->filter.deviceinterface.class, &event_iface->dbcc_classguid ); } + case DBT_DEVTYP_HANDLE: + { + DEV_BROADCAST_HANDLE *event_handle = (DEV_BROADCAST_HANDLE *)event; + const WCHAR *device_path = (const WCHAR *)&event_handle->dbch_data[event_handle->dbch_reserved]; + + return !wcsicmp( device_path, filter->filter.device.name_info->Name.Buffer ); + } default: FIXME( "Filter devicetype %lu not implemented \n", filter->devicetype ); } @@ -2098,9 +2106,15 @@ static DWORD WINAPI device_notify_proc( void *arg )
for (i = 0; i < details_copy_nelems; i++) { - const struct device_notification_details *details = &details_copy[i].details; + struct device_notification_details *details = &details_copy[i].details;
if (!notification_filter_matches( details, (DEV_BROADCAST_HDR *)buf )) continue; + if (details->devicetype == DBT_DEVTYP_HANDLE) + { + DEV_BROADCAST_HANDLE *handle = (DEV_BROADCAST_HANDLE *)buf; + handle->dbch_handle = details->filter.device.device; + handle->dbch_hdevnotify = details_copy[i].notify_handle; + } details->cb( details->handle, code, (DEV_BROADCAST_HDR *)buf ); } MIDL_user_free(buf); @@ -2133,6 +2147,9 @@ debugstr_device_notification_details( const struct device_notification_details * return wine_dbg_sprintf( "{%p %p DBT_DEVTYP_DEVICEINTERFACE {%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); } @@ -2183,6 +2200,8 @@ BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle ) EnterCriticalSection( &service_cs ); list_remove( ®istration->entry ); LeaveCriticalSection(&service_cs); + if (registration->details.devicetype == DBT_DEVTYP_HANDLE) + heap_free( registration->details.filter.device.name_info ); free( registration ); return TRUE; } diff --git a/dlls/user32/input.c b/dlls/user32/input.c index f0d33cf7540..3625219a079 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -30,6 +30,7 @@ #include "dbt.h" #include "wine/server.h" #include "wine/debug.h" +#include "wine/heap.h"
#include "wine/dbt.h"
@@ -534,11 +535,51 @@ static DWORD CALLBACK devnotify_window_callbackA(HANDLE handle, DWORD flags, DEV free( ifaceA ); return 0; } - default: - FIXME( "unimplemented W to A mapping for %#lx\n", header->dbch_devicetype ); + case DBT_DEVTYP_HANDLE: + { + const DEV_BROADCAST_HANDLE *handleW = (const DEV_BROADCAST_HANDLE *)header; + DEV_BROADCAST_HANDLE *handleA; + size_t lenA = 0; + size_t name_lenW = handleW->dbch_nameoffset == -1 + ? 0 + : wcslen( (WCHAR *)&handleW->dbch_data[handleW->dbch_nameoffset] ); + size_t data_size = handleW->dbch_nameoffset == -1 + ? handleW->dbch_reserved + : handleW->dbch_nameoffset + ( name_lenW * 3 + 1 ); + + handleA = malloc( offsetof( DEV_BROADCAST_HANDLE, dbch_data[data_size] )); + if (!handleA) + return 0; + + handleA->dbch_devicetype = DBT_DEVTYP_HANDLE; + if (handleW->dbch_nameoffset != -1) + { + lenA = WideCharToMultiByte( + CP_ACP, 0, (WCHAR *)&handleW->dbch_data[handleW->dbch_nameoffset], name_lenW + 1, + (CHAR *)&handleA->dbch_data[handleW->dbch_nameoffset], name_lenW * 3 + 1, NULL, + NULL ); + handleA->dbch_size = offsetof( DEV_BROADCAST_HANDLE, dbch_data[handleW->dbch_nameoffset + lenA + 1] ); + } + else + handleA->dbch_size = offsetof(DEV_BROADCAST_HANDLE, dbch_data[handleW->dbch_reserved]); + + handleA->dbch_reserved = 0; + handleA->dbch_handle = handleW->dbch_handle; + handleA->dbch_hdevnotify = handleW->dbch_hdevnotify; + handleA->dbch_eventguid = handleW->dbch_eventguid; + handleA->dbch_nameoffset = handleW->dbch_nameoffset; + memcpy( &handleA->dbch_data, &handleW->dbch_data, + handleW->dbch_nameoffset == -1 ? data_size : handleW->dbch_nameoffset ); + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)handleA, SMTO_ABORTIFHUNG, + 2000, NULL ); + free( handleA ); + return 0; + } case DBT_DEVTYP_OEM: break; + default: + FIXME( "unimplemented W to A mapping for %#lx\n", header->dbch_devicetype ); } }
@@ -597,7 +638,35 @@ HDEVNOTIFY WINAPI RegisterDeviceNotificationW( HANDLE handle, void *filter, DWOR } 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 = heap_alloc( size ); + if (!name_info) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return NULL; + } + + status = NtQueryObject( device, ObjectNameInformation, name_info, size, 0 ); + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError( status )); + heap_free( name_info ); + return NULL; + } + details.filter.device.name_info = name_info; + details.filter.device.device = handle->dbch_handle; } else { diff --git a/include/wine/dbt.h b/include/wine/dbt.h index 702fda17126..b8a82a87b08 100644 --- a/include/wine/dbt.h +++ b/include/wine/dbt.h @@ -37,6 +37,14 @@ struct device_notification_details BOOL all_classes; GUID class; } deviceinterface; + struct + { + /* The path for the device file the notification is originating from. */ + OBJECT_NAME_INFORMATION *name_info; + /* HANDLE to the device the event originates from. Is passed to the callback as-is, even + * if the user has closed this handle. */ + HANDLE device; + } device; } filter; };
diff --git a/programs/plugplay/main.c b/programs/plugplay/main.c index 8426f2204a3..1242b01ba2a 100644 --- a/programs/plugplay/main.c +++ b/programs/plugplay/main.c @@ -141,9 +141,13 @@ void __cdecl plugplay_send_event( DWORD code, const BYTE *data, unsigned int siz { struct listener *listener; struct event *event; + const DEV_BROADCAST_HDR *header = (const DEV_BROADCAST_HDR *)data;
- BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, code, (LPARAM)data ); - BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0 ); + if (header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + { + BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, code, (LPARAM)data ); + BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0 ); + }
EnterCriticalSection( &plugplay_cs );