From: Vibhav Pant vibhavp@gmail.com
--- dlls/ntoskrnl.exe/pnp.c | 6 ++-- dlls/sechost/service.c | 25 ++++++++++++-- dlls/user32/input.c | 72 +++++++++++++++++++++++++++++++++++++-- include/wine/dbt.h | 8 +++++ include/wine/plugplay.idl | 4 +-- programs/plugplay/main.c | 22 +++++++++--- 6 files changed, 122 insertions(+), 15 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index bb10c27fbee..b330a0eacc6 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -744,11 +744,11 @@ static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr ) return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode ); }
-static void send_devicechange( DWORD code, void *data, unsigned int size ) +static void send_devicechange( DWORD code, const WCHAR *path, void *data, unsigned int size ) { __TRY { - plugplay_send_event( code, data, size ); + plugplay_send_event( code, path, data, size ); } __EXCEPT(rpc_filter) { @@ -864,7 +864,7 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable broadcast->dbcc_classguid = iface->interface_class; lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 ); if (namelen > 1) broadcast->dbcc_name[1] = '\'; - send_devicechange( enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, broadcast, len ); + send_devicechange( enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, L"", broadcast, len ); heap_free( broadcast ); } return ret; diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c index 83bfc42c9c6..307b0f9ce94 100644 --- a/dlls/sechost/service.c +++ b/dlls/sechost/service.c @@ -36,6 +36,7 @@ #include "svcctl.h" #include "plugplay.h"
+#include "wine/heap.h" #include "wine/dbt.h"
WINE_DEFAULT_DEBUG_CHANNEL(service); @@ -1987,7 +1988,8 @@ struct device_notify_registration struct device_notification_details details; };
-static BOOL notification_filter_matches( const struct device_notification_details *filter, const DEV_BROADCAST_HDR *event ) +static BOOL notification_filter_matches( const struct device_notification_details *filter, + const WCHAR *path, const DEV_BROADCAST_HDR *event ) { if (!filter->devicetype) return TRUE; if (filter->devicetype != event->dbch_devicetype) return FALSE; @@ -2001,6 +2003,8 @@ static BOOL notification_filter_matches( const struct device_notification_detail return IsEqualGUID( &filter->filter.deviceinterface.class, &event_iface->dbcc_classguid ); } + case DBT_DEVTYP_HANDLE: + return !wcscmp( path, filter->filter.device.name_info->Name.Buffer ); default: FIXME( "Filter devicetype %lu not implemented \n", filter->devicetype ); } @@ -2027,6 +2031,7 @@ static DWORD WINAPI device_notify_proc( void *arg ) DWORD code = 0; unsigned int i, size; BYTE *buf; + WCHAR *path;
SetThreadDescription( GetCurrentThread(), L"wine_sechost_device_notify" );
@@ -2065,9 +2070,10 @@ static DWORD WINAPI device_notify_proc( void *arg ) for (;;) { buf = NULL; + path = NULL; __TRY { - code = plugplay_get_event( handle, &buf, &size ); + code = plugplay_get_event( handle, &path, &buf, &size ); err = ERROR_SUCCESS; } __EXCEPT(rpc_filter) @@ -2103,10 +2109,17 @@ static DWORD WINAPI device_notify_proc( void *arg ) { const struct device_notification_details *details = &details_copy[i].details;
- if (!notification_filter_matches( details, (DEV_BROADCAST_HDR *)buf )) continue; + if (!notification_filter_matches( details, path, (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); + MIDL_user_free( path ); }
__TRY @@ -2136,6 +2149,10 @@ 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 {%s %p}}", details->cb, details->handle, + debugstr_w( details->filter.device.name_info->Name.Buffer ), + details->filter.device.device ); default: return wine_dbg_sprintf( "{%p %p (unknown %#lx)}", details->cb, details->handle, details->devicetype); } @@ -2186,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) + 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 c85d10b0761..3afe3f32b32 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -534,9 +534,49 @@ static DWORD CALLBACK devnotify_window_callbackA(HANDLE handle, DWORD flags, DEV free( ifaceA ); return 0; } + 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_size - offsetof( DEV_BROADCAST_HANDLE, dbch_data ) + : 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 = handleW->dbch_size; + + 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; + } default: FIXME( "unimplemented W to A mapping for %#lx\n", header->dbch_devicetype ); - case DBT_DEVTYP_HANDLE: case DBT_DEVTYP_OEM: break; } @@ -597,7 +637,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/include/wine/plugplay.idl b/include/wine/plugplay.idl index a3e7b04bf30..04272457390 100644 --- a/include/wine/plugplay.idl +++ b/include/wine/plugplay.idl @@ -28,7 +28,7 @@ interface plugplay typedef [context_handle] void *plugplay_rpc_handle;
plugplay_rpc_handle plugplay_register_listener(); - DWORD plugplay_get_event([in] plugplay_rpc_handle handle, [out, size_is(,*size)] BYTE **data, [out] unsigned int *size); + DWORD plugplay_get_event([in] plugplay_rpc_handle handle, [out, string] WCHAR **path, [out, size_is(,*size)] BYTE **data, [out] unsigned int *size); void plugplay_unregister_listener([in] plugplay_rpc_handle handle); - void plugplay_send_event([in] DWORD event_code, [in, size_is(size)] const BYTE *data, [in] unsigned int size); + void plugplay_send_event([in] DWORD event_code, [in, string] const WCHAR *path, [in, size_is(size)] const BYTE *data, [in] unsigned int size); } diff --git a/programs/plugplay/main.c b/programs/plugplay/main.c index 8426f2204a3..6e52a3b710d 100644 --- a/programs/plugplay/main.c +++ b/programs/plugplay/main.c @@ -64,6 +64,7 @@ struct event { struct list entry; DWORD code; + WCHAR *path; BYTE *data; unsigned int size; }; @@ -108,7 +109,7 @@ plugplay_rpc_handle __cdecl plugplay_register_listener(void) return listener; }
-DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, BYTE **data, unsigned int *size ) +DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, WCHAR **path, BYTE **data, unsigned int *size ) { struct listener *listener = handle; struct event *event; @@ -128,6 +129,7 @@ DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, BYTE **data, unsig ret = event->code; *data = event->data; *size = event->size; + *path = event->path; free( event ); return ret; } @@ -137,14 +139,17 @@ void __cdecl plugplay_unregister_listener( plugplay_rpc_handle handle ) destroy_listener( handle ); }
-void __cdecl plugplay_send_event( DWORD code, const BYTE *data, unsigned int size ) +void __cdecl plugplay_send_event( DWORD code, const WCHAR *path, const BYTE *data, unsigned int size ) { 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 );
LIST_FOR_EACH_ENTRY(listener, &listener_list, struct listener, entry) @@ -158,6 +163,13 @@ void __cdecl plugplay_send_event( DWORD code, const BYTE *data, unsigned int siz break; }
+ event->path = NULL; + if (!(event->path = wcsdup( path ))) + { + free( event ); + break; + } + event->code = code; memcpy( event->data, data, size ); event->size = size;