[WIN32K:NTUSER]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 14 Feb 2016 18:41:49 +0000 (18:41 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 14 Feb 2016 18:41:49 +0000 (18:41 +0000)
- Cleanup window clipboard data while the window still exists and is not dereferenced.
- When a window is about to be destroyed (just before we send the WM_DESTROY message), if it is the current clipboard owner, make it release the clipboard. The WM_RENDERALLFORMATS message is then sent, and if needed, one WM_DRAWCLIPBOARD message.
- Send a WM_DRAWCLIPBOARD message when SetClipboardViewer is called.
WM_DRAWCLIPBOARD messages are sent as notifications to the corresponding windows.

svn path=/trunk/; revision=70744

reactos/win32ss/user/ntuser/clipboard.c
reactos/win32ss/user/ntuser/clipboard.h
reactos/win32ss/user/ntuser/window.c

index 5e153dc..ba1c323 100644 (file)
@@ -346,6 +346,43 @@ UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta)
     pWinSta->cNumClipFormats = 0;
 }
 
+/* UserClipboardRelease is called from IntSendDestroyMsg in window.c */
+VOID FASTCALL
+UserClipboardRelease(PWND pWindow)
+{
+    PWINSTATION_OBJECT pWinStaObj;
+
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        return;
+
+    co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_RENDERALLFORMATS, 0, 0);
+
+    /* If the window being destroyed is the current clipboard owner... */
+    if (pWindow == pWinStaObj->spwndClipOwner)
+    {
+        /* ... make it release the clipboard */
+        pWinStaObj->spwndClipOwner = NULL;
+    }
+
+    if (pWinStaObj->fClipboardChanged)
+    {
+        /* Add synthesized formats - they are rendered later */
+        IntAddSynthesizedFormats(pWinStaObj);
+
+        /* Notify viewer windows in chain */
+        pWinStaObj->fClipboardChanged = FALSE;
+        if (pWinStaObj->spwndClipViewer)
+        {
+            TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
+            // For 32-bit applications this message is sent as a notification
+            co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+        }
+    }
+
+    ObDereferenceObject(pWinStaObj);
+}
+
 /* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */
 VOID FASTCALL
 UserClipboardFreeWindow(PWND pWindow)
@@ -356,6 +393,12 @@ UserClipboardFreeWindow(PWND pWindow)
     if (!pWinStaObj)
         return;
 
+    if (pWindow == pWinStaObj->spwndClipOwner)
+    {
+        /* The owner window was destroyed */
+        pWinStaObj->spwndClipOwner = NULL;
+    }
+
     /* Check if clipboard is not locked by this window, if yes, unlock it */
     if (pWindow == pWinStaObj->spwndClipOpen)
     {
@@ -363,11 +406,6 @@ UserClipboardFreeWindow(PWND pWindow)
         pWinStaObj->spwndClipOpen = NULL;
         pWinStaObj->ptiClipLock = NULL;
     }
-    if (pWindow == pWinStaObj->spwndClipOwner)
-    {
-        /* The owner window was destroyed */
-        pWinStaObj->spwndClipOwner = NULL;
-    }
     /* Remove window from window chain */
     if (pWindow == pWinStaObj->spwndClipViewer)
         pWinStaObj->spwndClipViewer = NULL;
@@ -500,13 +538,13 @@ UserCloseClipboard(VOID)
         IntAddSynthesizedFormats(pWinStaObj);
 
         /* Notify viewer windows in chain */
+        pWinStaObj->fClipboardChanged = FALSE;
         if (pWinStaObj->spwndClipViewer)
         {
             TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
-            co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+            // For 32-bit applications this message is sent as a notification
+            co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
         }
-
-        pWinStaObj->fClipboardChanged = FALSE;
     }
 
 cleanup:
@@ -629,6 +667,7 @@ UserEmptyClipboard(VOID)
     if (pWinStaObj->spwndClipOwner)
     {
         TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p\n", pWinStaObj->spwndClipOwner->head.h);
+        // For 32-bit applications this message is sent as a notification
         co_IntSendMessageNoWait(pWinStaObj->spwndClipOwner->head.h, WM_DESTROYCLIPBOARD, 0, 0);
     }
 
@@ -1053,6 +1092,15 @@ NtUserSetClipboardViewer(HWND hWndNewViewer)
     /* Set new viewer window */
     pWinStaObj->spwndClipViewer = pWindow;
 
+    /* Notify viewer windows in chain */
+    pWinStaObj->fClipboardChanged = FALSE;
+    if (pWinStaObj->spwndClipViewer)
+    {
+        TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
+        // For 32-bit applications this message is sent as a notification
+        co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+    }
+
 cleanup:
     if (pWinStaObj)
         ObDereferenceObject(pWinStaObj);
index b983a17..5cbc08c 100644 (file)
@@ -10,6 +10,9 @@ typedef struct _CLIP
 UINT APIENTRY
 UserEnumClipboardFormats(UINT uFormat);
 
+VOID FASTCALL
+UserClipboardRelease(PWND pWindow);
+
 VOID FASTCALL
 UserClipboardFreeWindow(PWND pWindow);
 
index 9ca01b3..f89f08e 100644 (file)
@@ -424,10 +424,14 @@ static void IntSendDestroyMsg(HWND hWnd)
       }
    }
 
-   /*
-    * Send the WM_DESTROY to the window.
-    */
+   /* If the window being destroyed is the current clipboard owner... */
+   if (ti->ppi->prpwinsta != NULL && Window == ti->ppi->prpwinsta->spwndClipOwner)
+   {
+       /* ... make it release the clipboard */
+       UserClipboardRelease(Window);
+   }
 
+   /* Send the WM_DESTROY to the window */
    co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
 
    /*
@@ -554,6 +558,8 @@ LRESULT co_UserFreeWindow(PWND Window,
          co_IntSendMessage(UserHMGetHandle(Window), WM_NCDESTROY, 0, 0);
    }
 
+   UserClipboardFreeWindow(Window);
+
    DestroyTimersForWindow(ThreadData, Window);
 
    /* Unregister hot keys */
@@ -665,8 +671,6 @@ LRESULT co_UserFreeWindow(PWND Window,
 
    UserDereferenceObject(Window);
 
-   UserClipboardFreeWindow(Window);
-
    return 0;
 }