[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / wine / changenotify.c
index 15354a8..737c4d2 100644 (file)
@@ -58,6 +58,7 @@ typedef struct {
     OVERLAPPED overlapped; /* Overlapped structure */
     BYTE *buffer; /* Async buffer to fill */
     BYTE *backBuffer; /* Back buffer to swap buffer into */
+    struct _NOTIFICATIONLIST * pParent;
 } SHChangeNotifyEntryInternal, *LPNOTIFYREGISTER;
 #else
 typedef SHChangeNotifyEntry *LPNOTIFYREGISTER;
@@ -74,6 +75,9 @@ typedef struct _NOTIFICATIONLIST
        LONG wEventMask;        /* subscribed events */
        DWORD dwFlags;          /* client flags */
        ULONG id;
+#ifdef __REACTOS__
+    volatile LONG wQueuedCount;
+#endif
 } NOTIFICATIONLIST, *LPNOTIFICATIONLIST;
 
 #ifdef __REACTOS__
@@ -156,9 +160,22 @@ static const char * NodeName(const NOTIFICATIONLIST *item)
 static void DeleteNode(LPNOTIFICATIONLIST item)
 {
     UINT i;
+#ifdef __REACTOS__
+    LONG queued;
+#endif
 
     TRACE("item=%p\n", item);
 
+#ifdef __REACTOS__
+    queued = InterlockedCompareExchange(&item->wQueuedCount, 0, 0);
+    if (queued != 0)
+    {
+        TRACE("Not freeing, still %d queued events\n", queued);
+        return;
+    }
+    TRACE("Freeing for real! %p (%d) \n", item, item->cidl);
+#endif
+
     /* remove item from list */
     list_remove( &item->entry );
 
@@ -235,6 +252,7 @@ SHChangeNotifyRegister(
     item->cidl = cItems;
 #ifdef __REACTOS__
     item->apidl = SHAlloc(sizeof(SHChangeNotifyEntryInternal) * cItems);
+    item->wQueuedCount = 0;
 #else
     item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
 #endif
@@ -249,10 +267,23 @@ SHChangeNotifyRegister(
         item->apidl[i].buffer = SHAlloc(BUFFER_SIZE);
         item->apidl[i].backBuffer = SHAlloc(BUFFER_SIZE);
         item->apidl[i].overlapped.hEvent = &item->apidl[i];
+        item->apidl[i].pParent = item;
 
-        if (fSources & SHCNRF_InterruptLevel && _OpenDirectory( &item->apidl[i] ))
-            QueueUserAPC(_AddDirectoryProc, m_hThread, (ULONG_PTR) &item->apidl[i] );
-        else ERR("_OpenDirectory Failed\n");
+        if (fSources & SHCNRF_InterruptLevel)
+        {
+            if (_OpenDirectory( &item->apidl[i] ))
+            {
+                InterlockedIncrement(&item->wQueuedCount);
+                QueueUserAPC( _AddDirectoryProc, m_hThread, (ULONG_PTR) &item->apidl[i] );
+            }
+            else
+            {
+                CHAR buffer[MAX_PATH];
+                if (!SHGetPathFromIDListA( item->apidl[i].pidl, buffer ))
+                    strcpy( buffer, "<unknown>" );
+                ERR("_OpenDirectory failed for %s\n", buffer);
+            }
+        }
 #endif
     }
     item->hwnd = hwnd;
@@ -369,11 +400,11 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID
     }
 
     if( ( ( wEventId & SHCNE_NOITEMEVENTS ) && 
-          ( wEventId & ~SHCNE_NOITEMEVENTS ) ) ||
+          ( wEventId & ~(SHCNE_NOITEMEVENTS | SHCNE_INTERRUPT) ) ) ||
         ( ( wEventId & SHCNE_ONEITEMEVENTS ) && 
-          ( wEventId & ~SHCNE_ONEITEMEVENTS ) ) ||
+          ( wEventId & ~(SHCNE_ONEITEMEVENTS | SHCNE_INTERRUPT) ) ) ||
         ( ( wEventId & SHCNE_TWOITEMEVENTS ) && 
-          ( wEventId & ~SHCNE_TWOITEMEVENTS ) ) )
+          ( wEventId & ~(SHCNE_TWOITEMEVENTS | SHCNE_INTERRUPT) ) ) )
     {
         WARN("mutually incompatible events listed\n");
         return;
@@ -634,6 +665,7 @@ BOOL _OpenDirectory(LPNOTIFYREGISTER item)
         return FALSE;
 
     hr = IShellFolder_GetDisplayNameOf(psfDesktop, item->pidl, SHGDN_FORPARSING, &strFile);
+    IShellFolder_Release(psfDesktop);
     if (!SUCCEEDED(hr))
         return FALSE;
 
@@ -661,7 +693,7 @@ BOOL _OpenDirectory(LPNOTIFYREGISTER item)
 static void CALLBACK _RequestTermination(ULONG_PTR arg)
 {
     LPNOTIFYREGISTER item = (LPNOTIFYREGISTER) arg;
-    TRACE("_RequestTermination %p \n", item->hDirectory);
+    TRACE("_RequestTermination %p %p \n", item, item->hDirectory);
     if (!item->hDirectory || item->hDirectory == INVALID_HANDLE_VALUE) return;
 
     CancelIo(item->hDirectory);
@@ -682,12 +714,25 @@ _NotificationCompletion(DWORD dwErrorCode, // completion code
     LPNOTIFYREGISTER item = (LPNOTIFYREGISTER) lpOverlapped->hEvent;
     TRACE("_NotificationCompletion\n");
 
+#if 0
     if (dwErrorCode == ERROR_OPERATION_ABORTED)
     {
         /* Command was induced by CancelIo in the shutdown procedure. */
         TRACE("_NotificationCompletion ended.\n");
         return;
     }
+#endif
+
+#ifdef __REACTOS__
+    /* If the FSD doesn't support directory change notifications, there's no
+     * no need to retry and requeue notification
+     */
+    if (dwErrorCode == ERROR_INVALID_FUNCTION)
+    {
+        WARN("Directory watching not supported\n");
+        goto quit;
+    }
+#endif
 
     /* This likely means overflow, so force whole directory refresh. */
     if (!dwNumberOfBytesTransfered)
@@ -702,7 +747,11 @@ _NotificationCompletion(DWORD dwErrorCode, // completion code
                        item->pidl,
                        NULL);
 
+#ifdef __REACTOS__
+        goto quit;
+#else
         return;
+#endif
     }
 
     /*
@@ -719,12 +768,21 @@ _NotificationCompletion(DWORD dwErrorCode, // completion code
     _BeginRead(item);
 
     _ProcessNotification(item);
+
+#ifdef __REACTOS__
+quit:
+    InterlockedDecrement(&item->pParent->wQueuedCount);
+    DeleteNode(item->pParent);
+#endif
 }
 
 static VOID _BeginRead(LPNOTIFYREGISTER item )
 {
     TRACE("_BeginRead %p \n", item->hDirectory);
 
+#ifdef __REACTOS__
+    InterlockedIncrement(&item->pParent->wQueuedCount);
+#endif
     /* This call needs to be reissued after every APC. */
     if (!ReadDirectoryChangesW(item->hDirectory, // handle to directory
                                item->buffer, // read results buffer
@@ -734,12 +792,22 @@ static VOID _BeginRead(LPNOTIFYREGISTER item )
                                NULL, // bytes returned
                                &item->overlapped, // overlapped buffer
                                _NotificationCompletion)) // completion routine
-        ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p) Code: %u \n",
+#ifdef __REACTOS__
+    {
+#endif
+        ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p, %p, %p) Code: %u \n",
+            item,
+            item->pParent,
             item->hDirectory,
             item->buffer,
             &item->overlapped,
             _NotificationCompletion,
             GetLastError());
+#ifdef __REACTOS__
+        InterlockedDecrement(&item->pParent->wQueuedCount);
+        DeleteNode(item->pParent);
+    }
+#endif
 }
 
 DWORD _MapAction(DWORD dwAction, BOOL isDir)