ntoskrnl.exe: Broadcast device notifications to registered handlers.

Based on a patch by Micah N Gorrell.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Zebediah Figura 2020-05-05 11:25:39 -05:00 committed by Alexandre Julliard
parent 6cf777ebd5
commit d80101f17a
5 changed files with 82 additions and 4 deletions

View File

@ -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

View File

@ -0,0 +1,2 @@
#pragma makedep client
#include "wine/plugplay.idl"

View File

@ -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 )

View File

@ -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);
}

View File

@ -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;