[Wine-patches] [eterhack 12/24] ntoskrnl.exe: Partially implement Io*PlugPlayNotification.

Alexander Morozov =?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Ср Мар 4 12:25:21 MSK 2009


---
 dlls/ntoskrnl.exe/ntoskrnl.c |  129 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 123 insertions(+), 6 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 18fc88d..097a696 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -25,6 +25,7 @@
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
+#define INITGUID
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -39,6 +40,7 @@
 #include "cfgmgr32.h"
 #include "excpt.h"
 #include "ddk/ntddk.h"
+#include "ddk/wdmguid.h"
 #include "wine/unicode.h"
 #include "wine/server.h"
 #include "wine/list.h"
@@ -105,6 +107,23 @@ struct InterfaceInstance
     UNICODE_STRING target;
 };
 
+static struct list InterfaceChangeNotifications = LIST_INIT(InterfaceChangeNotifications);
+
+struct InterfaceChangeNotification
+{
+    struct list entry;
+    GUID interface_class;
+    PDRIVER_NOTIFICATION_CALLBACK_ROUTINE callback;
+    void *context;
+};
+
+struct callback
+{
+    struct list entry;
+    PDRIVER_NOTIFICATION_CALLBACK_ROUTINE routine;
+    void *context;
+};
+
 #define IOCTL_WINE_DRIVER_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x100, \
         METHOD_BUFFERED, FILE_ANY_ACCESS)
 
@@ -1459,9 +1478,37 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( PUNICODE_STRING SymbolicLinkName,
 
     if (Enable)
     {
+        struct list callbacks = LIST_INIT(callbacks);
         struct InterfaceInstance *interf;
-        NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
-
+        struct InterfaceChangeNotification *notification;
+        struct callback *cb, *cb2;
+        DEVICE_INTERFACE_CHANGE_NOTIFICATION change_notification;
+        NTSTATUS status, callback_status;
+        UNICODE_STRING guid_str;
+        WCHAR *ptr, *guid_strW;
+        USHORT len = 0;
+        GUID guid;
+
+        /* get interface class GUID from SymbolicLinkName */
+        ptr = SymbolicLinkName->Buffer + SymbolicLinkName->Length / sizeof(WCHAR);
+        while (ptr-- > SymbolicLinkName->Buffer)
+        {
+            if (*ptr == '#') break;
+            ++len;
+        }
+        ++ptr;
+        if (len != 38) return STATUS_INVALID_PARAMETER;
+        guid_strW = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
+        if (guid_strW == NULL) return STATUS_NO_MEMORY;
+        memcpy( guid_strW, ptr, len * sizeof(WCHAR) );
+        guid_strW[len] = 0;
+        RtlInitUnicodeString( &guid_str, guid_strW );
+        status = RtlGUIDFromString( &guid_str, &guid );
+        HeapFree( GetProcessHeap(), 0, guid_strW );
+        if (status != STATUS_SUCCESS) return status;
+
+        /* create symbolic link if interface is registered */
+        status = STATUS_OBJECT_NAME_NOT_FOUND;
         EnterCriticalSection( &cs );
         LIST_FOR_EACH_ENTRY( interf, &Interfaces, struct InterfaceInstance, entry )
         {
@@ -1472,8 +1519,51 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState( PUNICODE_STRING SymbolicLinkName,
                 break;
             }
         }
+        if (status != STATUS_SUCCESS)
+        {
+            LeaveCriticalSection( &cs );
+            return status;
+        }
+
+        /* call callback routines for registered interface change notifications */
+        LIST_FOR_EACH_ENTRY( notification, &InterfaceChangeNotifications,
+                struct InterfaceChangeNotification, entry )
+        {
+            if (!memcmp( &guid, &notification->interface_class, sizeof(guid) ))
+            {
+                cb = HeapAlloc( GetProcessHeap(), 0, sizeof(*cb) );
+                if (cb == NULL) break;
+                cb->routine = notification->callback;
+                cb->context = notification->context;
+                list_add_tail( &callbacks, &cb->entry );
+            }
+        }
         LeaveCriticalSection( &cs );
-        return status;
+
+        change_notification.Version = 1;
+        change_notification.Size = sizeof(change_notification);
+        change_notification.Event = GUID_DEVICE_INTERFACE_ARRIVAL;
+        change_notification.InterfaceClassGuid = guid;
+        change_notification.SymbolicLinkName = SymbolicLinkName;
+
+        LIST_FOR_EACH_ENTRY_SAFE( cb, cb2, &callbacks, struct callback, entry )
+        {
+            if (TRACE_ON(relay))
+                DPRINTF( "%04x:Call callback %p (notification=%p,context=%p)\n",
+                         GetCurrentThreadId(), cb->routine, &change_notification,
+                         cb->context );
+
+            callback_status = cb->routine( &change_notification, cb->context );
+
+            if (TRACE_ON(relay))
+                DPRINTF( "%04x:Ret  callback %p (notification=%p,context=%p) retval=%08x\n",
+                         GetCurrentThreadId(), cb->routine, &change_notification,
+                         cb->context, callback_status );
+
+            list_remove( &cb->entry );
+            HeapFree( GetProcessHeap(), 0, cb );
+        }
+        return STATUS_SUCCESS;
     }
     else
     {
@@ -1642,10 +1732,30 @@ NTSTATUS WINAPI IoRegisterPlugPlayNotification( IO_NOTIFICATION_EVENT_CATEGORY
                                                 CallbackRoutine, PVOID Context,
                                                 PVOID *NotificationEntry )
 {
-    FIXME( "stub: %u %u %p %p %p %p %p\n", EventCategory, EventCategoryFlags,
+    TRACE( "%u %u %p %p %p %p %p\n", EventCategory, EventCategoryFlags,
            EventCategoryData, DriverObject, CallbackRoutine, Context,
            NotificationEntry );
-    return STATUS_SUCCESS;
+
+    if (EventCategory == EventCategoryDeviceInterfaceChange)
+    {
+        struct InterfaceChangeNotification *notification =
+                HeapAlloc( GetProcessHeap(), 0, sizeof(*notification) );
+
+        if (notification == NULL) return STATUS_NO_MEMORY;
+        notification->interface_class = *(GUID *)EventCategoryData;
+        notification->callback = CallbackRoutine;
+        notification->context = Context;
+        EnterCriticalSection( &cs );
+        list_add_tail( &InterfaceChangeNotifications, &notification->entry );
+        LeaveCriticalSection( &cs );
+        *NotificationEntry = notification;
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        FIXME( "event category %u is not supported\n", EventCategory );
+        return STATUS_NOT_IMPLEMENTED;
+    }
 }
 
 
@@ -1654,7 +1764,14 @@ NTSTATUS WINAPI IoRegisterPlugPlayNotification( IO_NOTIFICATION_EVENT_CATEGORY
  */
 NTSTATUS WINAPI IoUnregisterPlugPlayNotification( PVOID NotificationEntry )
 {
-    FIXME( "stub: %p\n", NotificationEntry );
+    struct InterfaceChangeNotification *notification = NotificationEntry;
+
+    TRACE( "%p\n", NotificationEntry );
+
+    EnterCriticalSection( &cs );
+    list_remove( &notification->entry );
+    LeaveCriticalSection( &cs );
+    HeapFree( GetProcessHeap(), 0, notification );
     return STATUS_SUCCESS;
 }
 
-- 
1.6.1.3.GIT



Подробная информация о списке рассылки Wine-patches