[PATCH v2 5/8] ntoskrnl.exe: Implement sending of device notifications
Micah N Gorrell
mgorrell at codeweavers.com
Tue Sep 10 16:59:15 CDT 2019
Send device notifications via RPC to services.exe
Signed-off-by: Micah N Gorrell <mgorrell at codeweavers.com>
---
dlls/ntoskrnl.exe/Makefile.in | 4 +-
dlls/ntoskrnl.exe/ntoskrnl_private.h | 5 +
dlls/ntoskrnl.exe/pnp.c | 1 +
dlls/ntoskrnl.exe/rpc.c | 182 +++++++++++++++++++++++++++
dlls/ntoskrnl.exe/svcctl.idl | 3 +
include/wine/svcctl.idl | 7 ++
programs/services/rpc.c | 45 +++++++
7 files changed, 246 insertions(+), 1 deletion(-)
create mode 100644 dlls/ntoskrnl.exe/rpc.c
create mode 100644 dlls/ntoskrnl.exe/svcctl.idl
diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in
index a75ca9768d..441238177a 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
-DELAYIMPORTS = setupapi user32
+DELAYIMPORTS = setupapi user32 rpcrt4
EXTRADLLFLAGS = -mno-cygwin
@@ -9,6 +9,8 @@ C_SRCS = \
instr.c \
ntoskrnl.c \
pnp.c \
+ rpc.c \
sync.c
+IDL_SRCS = svcctl.idl
RC_SRCS = ntoskrnl.rc
diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h
index b5244ef164..ded5c0bec4 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl_private.h
+++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h
@@ -22,6 +22,8 @@
#define __WINE_NTOSKRNL_PRIVATE_H
#include "wine/asm.h"
+#include "winuser.h"
+#include "dbt.h"
static inline LPCSTR debugstr_us( const UNICODE_STRING *us )
{
@@ -86,4 +88,7 @@ static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
'\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
'\\','S','e','r','v','i','c','e','s',
'\\',0};
+
+DWORD send_device_notification( DEV_BROADCAST_DEVICEINTERFACE_W *broadcast, BOOL enable );
+
#endif
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c
index 03c4c401f9..645b04fd28 100644
--- a/dlls/ntoskrnl.exe/pnp.c
+++ b/dlls/ntoskrnl.exe/pnp.c
@@ -605,6 +605,7 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable
lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 );
BroadcastSystemMessageW( BSF_FORCEIFHUNG | BSF_QUERY, NULL, WM_DEVICECHANGE,
enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, (LPARAM)broadcast );
+ send_device_notification( broadcast, enable );
heap_free( broadcast );
}
diff --git a/dlls/ntoskrnl.exe/rpc.c b/dlls/ntoskrnl.exe/rpc.c
new file mode 100644
index 0000000000..a4779a168a
--- /dev/null
+++ b/dlls/ntoskrnl.exe/rpc.c
@@ -0,0 +1,182 @@
+/*
+ * RPC connection with services.exe
+ *
+ * Copyright 1995 Sven Verdoolaege
+ * Copyright 2005 Mike McCormack
+ * Copyright 2007 Rolf Kalbermatter
+ * Copyright 2019 Micah N Gorrell for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winsvc.h"
+#include "winternl.h"
+#include "dbt.h"
+#include "svcctl.h"
+#include "wine/exception.h"
+#include "ddk/ntifs.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/rbtree.h"
+
+#include "ntoskrnl_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
+
+/******************************************************************************
+ * RPC connection with services.exe
+ */
+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 handle_t rpc_wstr_bind(RPC_WSTR str)
+{
+ WCHAR transport[] = SVCCTL_TRANSPORT;
+ WCHAR endpoint[] = SVCCTL_ENDPOINT;
+ RPC_WSTR binding_str;
+ RPC_STATUS status;
+ handle_t rpc_handle;
+
+ status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str);
+ if (status != RPC_S_OK)
+ {
+ ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
+ return NULL;
+ }
+
+ status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
+ RpcStringFreeW(&binding_str);
+
+ if (status != RPC_S_OK)
+ {
+ ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
+ return NULL;
+ }
+
+ return rpc_handle;
+}
+
+static handle_t rpc_cstr_bind(RPC_CSTR str)
+{
+ RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
+ RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
+ RPC_CSTR binding_str;
+ RPC_STATUS status;
+ handle_t rpc_handle;
+
+ status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str);
+ if (status != RPC_S_OK)
+ {
+ ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
+ return NULL;
+ }
+
+ status = RpcBindingFromStringBindingA(binding_str, &rpc_handle);
+ RpcStringFreeA(&binding_str);
+
+ if (status != RPC_S_OK)
+ {
+ ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
+ return NULL;
+ }
+
+ return rpc_handle;
+}
+
+DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName)
+{
+ return rpc_cstr_bind((RPC_CSTR)MachineName);
+}
+
+DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h)
+{
+ RpcBindingFree(&h);
+}
+
+DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
+{
+ return rpc_wstr_bind((RPC_WSTR)MachineName);
+}
+
+DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
+{
+ RpcBindingFree(&h);
+}
+
+DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName)
+{
+ return rpc_wstr_bind((RPC_WSTR)MachineName);
+}
+
+DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h)
+{
+ RpcBindingFree(&h);
+}
+
+static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
+{
+ return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
+}
+
+static DWORD map_exception_code(DWORD exception_code)
+{
+ switch (exception_code)
+ {
+ case RPC_X_NULL_REF_POINTER:
+ return ERROR_INVALID_ADDRESS;
+ case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
+ case RPC_X_BYTE_COUNT_TOO_SMALL:
+ return ERROR_INVALID_PARAMETER;
+ case RPC_S_INVALID_BINDING:
+ case RPC_X_SS_IN_NULL_CONTEXT:
+ return ERROR_INVALID_HANDLE;
+ default:
+ return exception_code;
+ }
+}
+
+DWORD send_device_notification(DEV_BROADCAST_DEVICEINTERFACE_W *broadcast, BOOL enable)
+{
+ DWORD err;
+
+ __TRY
+ {
+ err = svcctl_SendDeviceNotification(NULL,
+ enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE,
+ (const BYTE *) broadcast, broadcast->dbcc_size);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ err = map_exception_code(GetExceptionCode());
+ }
+ __ENDTRY
+
+ TRACE("send result (%d)\n", err);
+ return err;
+}
diff --git a/dlls/ntoskrnl.exe/svcctl.idl b/dlls/ntoskrnl.exe/svcctl.idl
new file mode 100644
index 0000000000..b1bc8545d7
--- /dev/null
+++ b/dlls/ntoskrnl.exe/svcctl.idl
@@ -0,0 +1,3 @@
+#pragma makedep client
+
+#include "wine/svcctl.idl"
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index 0d75cf73c4..2399f3f5fd 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -818,4 +818,11 @@ typedef [switch_type(DWORD)] union _SC_RPC_SERVICE_CONTROL_OUT_PARAMSW {
[out] DWORD *event_code,
[out, size_is(,*event_size)] BYTE **event,
[out] DWORD *event_size);
+
+ /* Not compatible with Windows function 59 */
+ DWORD svcctl_SendDeviceNotification(
+ [in, string, unique] SVCCTL_HANDLEW machinename,
+ [in] DWORD event_code,
+ [in, size_is(event_size)] const BYTE *event,
+ [in] DWORD event_size);
}
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 9bd43267b9..d66a575a13 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -2250,6 +2250,51 @@ DWORD __cdecl svcctl_GetDeviceNotificationResults(
return ERROR_SUCCESS;
}
+DWORD __cdecl svcctl_SendDeviceNotification(
+ MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
+ DWORD code,
+ const BYTE *event_buf,
+ DWORD event_buf_size)
+{
+ struct sc_dev_notify_handle *listener;
+ struct devnotify_event *event;
+
+ if (!event_buf)
+ return ERROR_INVALID_PARAMETER;
+
+ EnterCriticalSection(&device_notifications_cs);
+ LIST_FOR_EACH_ENTRY(listener, &devnotify_listeners, struct sc_dev_notify_handle, entry)
+ {
+ WINE_TRACE("Triggering listener %p\n", listener);
+
+ event = HeapAlloc(GetProcessHeap(), 0, sizeof(struct devnotify_event));
+ if (event)
+ event->data = MIDL_user_allocate(event_buf_size);
+
+ if (!event || !event->data)
+ {
+ HeapFree(GetProcessHeap(), 0, event);
+
+ LeaveCriticalSection(&device_notifications_cs);
+ return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+ }
+
+ event->code = code;
+ memcpy(event->data, event_buf, event_buf_size);
+ event->data_size = event_buf_size;
+
+ EnterCriticalSection(&listener->cs);
+ list_add_tail(&listener->event_list, &event->entry);
+ LeaveCriticalSection(&listener->cs);
+
+ SetEvent(listener->event);
+ }
+ WINE_TRACE("Done triggering registrations\n");
+ LeaveCriticalSection(&device_notifications_cs);
+
+ return ERROR_SUCCESS;
+}
+
DWORD RPC_Init(void)
{
WCHAR transport[] = SVCCTL_TRANSPORT;
--
2.23.0
More information about the wine-devel
mailing list