[PATCH 2/4] ntoskrnl.exe: Broadcast device notifications to registered handlers.

Zebediah Figura z.figura12 at gmail.com
Tue May 5 11:25:39 CDT 2020


Based on a patch by Micah N Gorrell.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/ntoskrnl.exe/Makefile.in  |  5 +++-
 dlls/ntoskrnl.exe/plugplay.idl |  2 ++
 dlls/ntoskrnl.exe/pnp.c        | 50 ++++++++++++++++++++++++++++++++--
 include/wine/plugplay.idl      |  1 +
 programs/plugplay/main.c       | 28 +++++++++++++++++++
 5 files changed, 82 insertions(+), 4 deletions(-)
 create mode 100644 dlls/ntoskrnl.exe/plugplay.idl

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




More information about the wine-devel mailing list