diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in index 67afa8f9d8a..85bc1ce6987 100644 --- a/dlls/ntoskrnl.exe/Makefile.in +++ b/dlls/ntoskrnl.exe/Makefile.in @@ -1,7 +1,7 @@ MODULE = ntoskrnl.exe IMPORTLIB = ntoskrnl IMPORTS = advapi32 hal msvcrt -DELAYIMPORTS = setupapi user32 +DELAYIMPORTS = rpcrt4 setupapi user32 EXTRADLLFLAGS = -mno-cygwin @@ -12,3 +12,6 @@ C_SRCS = \ sync.c RC_SRCS = ntoskrnl.rc + +IDL_SRCS = \ + plugplay.idl diff --git a/dlls/ntoskrnl.exe/plugplay.idl b/dlls/ntoskrnl.exe/plugplay.idl new file mode 100644 index 00000000000..05e040388e4 --- /dev/null +++ b/dlls/ntoskrnl.exe/plugplay.idl @@ -0,0 +1,2 @@ +#pragma makedep client +#include "wine/plugplay.idl" diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 9e4c2c1416a..470e2368fb5 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -39,10 +39,12 @@ #include "ddk/wdm.h" #include "ddk/ntifs.h" #include "wine/debug.h" +#include "wine/exception.h" #include "wine/heap.h" #include "wine/rbtree.h" #include "ntoskrnl_private.h" +#include "plugplay.h" #include "initguid.h" DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); @@ -651,6 +653,35 @@ static NTSTATUS create_device_symlink( DEVICE_OBJECT *device, UNICODE_STRING *sy return ret; } +void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len ) +{ + return heap_alloc( len ); +} + +void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr ) +{ + heap_free( ptr ); +} + +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 ) +{ + BroadcastSystemMessageW( BSF_FORCEIFHUNG | BSF_QUERY, NULL, WM_DEVICECHANGE, code, (LPARAM)data ); + __TRY + { + plugplay_send_event( code, data, size ); + } + __EXCEPT(rpc_filter) + { + WARN("Failed to send event, exception %#x.\n", GetExceptionCode()); + } + __ENDTRY +} + /*********************************************************************** * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@) */ @@ -756,9 +787,7 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; broadcast->dbcc_classguid = iface->interface_class; lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 ); - BroadcastSystemMessageW( BSF_FORCEIFHUNG | BSF_QUERY, NULL, WM_DEVICECHANGE, - enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, (LPARAM)broadcast ); - + send_devicechange( enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, broadcast, len ); heap_free( broadcast ); } return ret; @@ -1002,12 +1031,26 @@ static NTSTATUS WINAPI pnp_manager_driver_entry( DRIVER_OBJECT *driver, UNICODE_ void pnp_manager_start(void) { static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0}; + WCHAR endpoint[] = L"\\pipe\\wine_plugplay"; + WCHAR protseq[] = L"ncalrpc"; UNICODE_STRING driver_nameU; + RPC_WSTR binding_str; NTSTATUS status; + RPC_STATUS err; RtlInitUnicodeString( &driver_nameU, driver_nameW ); if ((status = IoCreateDriver( &driver_nameU, pnp_manager_driver_entry ))) ERR("Failed to create PnP manager driver, status %#x.\n", status); + + if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str ))) + { + ERR("RpcStringBindingCompose() failed, error %#x\n", err); + return; + } + err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle ); + RpcStringFreeW( &binding_str ); + if (err) + ERR("RpcBindingFromStringBinding() failed, error %#x\n", err); } static void destroy_root_pnp_device( struct wine_rb_entry *entry, void *context ) @@ -1020,6 +1063,7 @@ void pnp_manager_stop(void) { wine_rb_destroy( &root_pnp_devices, destroy_root_pnp_device, NULL ); IoDeleteDriver( pnp_manager ); + RpcBindingFree( &plugplay_binding_handle ); } void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) diff --git a/include/wine/plugplay.idl b/include/wine/plugplay.idl index 7cc59191248..8123b733ad1 100644 --- a/include/wine/plugplay.idl +++ b/include/wine/plugplay.idl @@ -29,4 +29,5 @@ interface plugplay 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); 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); } diff --git a/programs/plugplay/main.c b/programs/plugplay/main.c index 59561dca503..00af2b0adfa 100644 --- a/programs/plugplay/main.c +++ b/programs/plugplay/main.c @@ -136,6 +136,34 @@ 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 ) +{ + struct listener *listener; + struct event *event; + + EnterCriticalSection( &plugplay_cs ); + + LIST_FOR_EACH_ENTRY(listener, &listener_list, struct listener, entry) + { + if (!(event = malloc( sizeof(*event) ))) + break; + + if (!(event->data = malloc( size ))) + { + free( event ); + break; + } + + event->code = code; + memcpy( event->data, data, size ); + event->size = size; + list_add_tail( &listener->events, &event->entry ); + WakeConditionVariable( &listener->cv ); + } + + LeaveCriticalSection( &plugplay_cs ); +} + static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) { SERVICE_STATUS status;