[WIN32SS][USER32] Add Ghost codes (retrial of #1100) (#1112)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Tue, 11 Dec 2018 03:30:59 +0000 (12:30 +0900)
committerGitHub <noreply@github.com>
Tue, 11 Dec 2018 03:30:59 +0000 (12:30 +0900)
CORE-11944

win32ss/include/ghostwnd.h [new file with mode: 0644]
win32ss/user/ntuser/class.h
win32ss/user/ntuser/ghost.c
win32ss/user/ntuser/ghost.h
win32ss/user/ntuser/message.c
win32ss/user/user32/controls/ghost.c

diff --git a/win32ss/include/ghostwnd.h b/win32ss/include/ghostwnd.h
new file mode 100644 (file)
index 0000000..6907580
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * PROJECT:     ReactOS header
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Ghost window
+ * COPYRIGHT:   Copyright 2018 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
+ */
+#ifndef REACTOS_GHOST_WND_INCLUDED
+#define REACTOS_GHOST_WND_INCLUDED
+
+#define GHOSTCLASSNAME L"Ghost"
+#define GHOST_PROP L"GhostProp"
+
+typedef struct GHOST_DATA
+{
+    HWND hwndTarget;
+    HBITMAP hbm32bpp;
+    BOOL bDestroyTarget;
+} GHOST_DATA;
+
+#endif
index c5b3e83..0c41dc3 100644 (file)
@@ -66,4 +66,12 @@ ProbeAndCaptureUnicodeStringOrAtom(
     _Out_ _When_(return>=0, _At_(pustrOut->Buffer, _Post_ _Notnull_)) PUNICODE_STRING pustrOut,
     __in_data_source(USER_MODE) _In_ PUNICODE_STRING pustrUnsafe);
 
+BOOL FASTCALL LookupFnIdToiCls(int FnId, int *iCls);
+
+INT
+UserGetClassName(IN PCLS Class,
+                 IN OUT PUNICODE_STRING ClassName,
+                 IN RTL_ATOM Atom,
+                 IN BOOL Ansi);
+
 /* EOF */
index 726fe8f..efbc5d2 100644 (file)
 /*
  * PROJECT:     ReactOS user32.dll
  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE:     Ghost window handling
+ * PURPOSE:     Window ghosting feature
  * COPYRIGHT:   Copyright 2018 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
  */
 
 #include <win32k.h>
+#include "ghostwnd.h"
 
-BOOL FASTCALL IntGoGhost(PWND Window, BOOL bGo)
+#define NDEBUG
+#include <debug.h>
+
+static UNICODE_STRING GhostClass = RTL_CONSTANT_STRING(GHOSTCLASSNAME);
+static UNICODE_STRING GhostProp = RTL_CONSTANT_STRING(GHOST_PROP);
+
+BOOL FASTCALL IntIsGhostWindow(PWND Window)
+{
+    BOOLEAN Ret = FALSE;
+    UNICODE_STRING ClassName;
+    INT iCls, Len;
+    RTL_ATOM Atom = 0;
+
+    if (!Window)
+        return FALSE;
+
+    if (Window->fnid && !(Window->fnid & FNID_DESTROY))
+    {
+        if (LookupFnIdToiCls(Window->fnid, &iCls))
+        {
+            Atom = gpsi->atomSysClass[iCls];
+        }
+    }
+
+    // check class name
+    RtlInitUnicodeString(&ClassName, NULL);
+    Len = UserGetClassName(Window->pcls, &ClassName, Atom, FALSE);
+    if (Len > 0)
+    {
+        Ret = RtlEqualUnicodeString(&ClassName, &GhostClass, TRUE);
+    }
+    else
+    {
+        DPRINT1("Unable to get class name\n");
+    }
+    RtlFreeUnicodeString(&ClassName);
+
+    return Ret;
+}
+
+HWND FASTCALL IntGhostWindowFromHungWindow(PWND pHungWnd)
+{
+    RTL_ATOM Atom;
+    HWND hwndGhost;
+
+    if (!IntGetAtomFromStringOrAtom(&GhostProp, &Atom))
+        ASSERT(FALSE);
+
+    hwndGhost = UserGetProp(pHungWnd, Atom, TRUE);
+    if (hwndGhost)
+    {
+        if (ValidateHwndNoErr(hwndGhost))
+            return hwndGhost;
+
+        DPRINT("Not a window\n");
+    }
+
+    return NULL;
+}
+
+HWND FASTCALL UserGhostWindowFromHungWindow(HWND hwndHung)
 {
+    PWND pHungWnd = ValidateHwndNoErr(hwndHung);
+    if (!pHungWnd)
+    {
+        DPRINT("Not a window\n");
+        return NULL;
+    }
+    return IntGhostWindowFromHungWindow(pHungWnd);
+}
+
+HWND FASTCALL IntHungWindowFromGhostWindow(PWND pGhostWnd)
+{
+    const GHOST_DATA *UserData;
+    HWND hwndTarget;
+
+    if (!IntIsGhostWindow(pGhostWnd))
+    {
+        DPRINT("Not a ghost window\n");
+        return NULL;
+    }
+
+    UserData = (const GHOST_DATA *)pGhostWnd->dwUserData;
+    if (UserData)
+    {
+        _SEH2_TRY
+        {
+            ProbeForRead(UserData, sizeof(GHOST_DATA), 1);
+            hwndTarget = UserData->hwndTarget;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            DPRINT1("Exception!\n");
+            hwndTarget = NULL;
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        DPRINT("No user data\n");
+        hwndTarget = NULL;
+    }
+
+    if (hwndTarget)
+    {
+        if (ValidateHwndNoErr(hwndTarget))
+            return hwndTarget;
+
+        DPRINT1("Not a window\n");
+    }
+
+    return NULL;
+}
+
+HWND FASTCALL UserHungWindowFromGhostWindow(HWND hwndGhost)
+{
+    PWND pGhostWnd = ValidateHwndNoErr(hwndGhost);
+    return IntHungWindowFromGhostWindow(pGhostWnd);
+}
+
+BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung)
+{
+    PWND pHungWnd = ValidateHwndNoErr(hwndHung);
+    if (!pHungWnd)
+    {
+        DPRINT1("Not a window\n");
+        return FALSE;   // not a window
+    }
+
+    if (!MsqIsHung(pHungWnd->head.pti))
+    {
+        DPRINT1("Not hung window\n");
+        return FALSE;   // not hung window
+    }
+
+    if (!(pHungWnd->style & WS_VISIBLE))
+        return FALSE;   // invisible
+
+    if (pHungWnd->style & WS_CHILD)
+        return FALSE;   // child
+
+    if (IntIsGhostWindow(pHungWnd))
+    {
+        DPRINT1("IntIsGhostWindow\n");
+        return FALSE;   // ghost window cannot be ghosted
+    }
+
+    if (IntGhostWindowFromHungWindow(pHungWnd))
+    {
+        DPRINT("Already ghosting\n");
+        return FALSE;   // already ghosting
+    }
+
     // TODO:
     // 1. Create a thread.
     // 2. Create a ghost window in the thread.
     // 3. Do message loop in the thread
-    static int bWarnedOnce = 0;
-    if (!bWarnedOnce)
     {
-        bWarnedOnce++;
-        STUB;
+        static int bWarnedOnce = 0;
+        if (!bWarnedOnce)
+        {
+            bWarnedOnce++;
+            STUB;
+        }
     }
+
     return FALSE;
 }
index c348bf1..cd7b45c 100644 (file)
@@ -1 +1 @@
-BOOL FASTCALL IntGoGhost(PWND Window, BOOL bGo);
+BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung);
index 0de5f3f..7564109 100644 (file)
@@ -1441,9 +1441,6 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
             /* FIXME: Set a LastError? */
             RETURN( FALSE);
         }
-
-        TRACE("Let's go Ghost!\n");
-        IntGoGhost(Window, TRUE);
     }
 
     if (Window->state & WNDS_DESTROYED)
@@ -1471,6 +1468,11 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
 
     if (Status == STATUS_TIMEOUT)
     {
+        if (MsqIsHung(ptiSendTo))
+        {
+            TRACE("Let's go Ghost!\n");
+            IntMakeHungWindowGhosted(hWnd);
+        }
 /*
  *  MSDN says:
  *  Microsoft Windows 2000: If GetLastError returns zero, then the function
index ccc9a6c..0abc064 100644 (file)
@@ -7,12 +7,12 @@
 
 #include <user32.h>
 #include <strsafe.h>
+#include "ghostwnd.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ghost);
 
 #define GHOST_TIMER_ID  0xFACEDEAD
 #define GHOST_INTERVAL  1000        // one second
-#define GHOST_PROP      L"GhostProp"
 
 const struct builtin_class_descr GHOST_builtin_class =
 {
@@ -105,13 +105,6 @@ IntMakeGhostImage(HBITMAP hbm)
 
 /****************************************************************************/
 
-typedef struct GHOST_DATA
-{
-    HWND hwndTarget;
-    HBITMAP hbm32bpp;
-    BOOL bDestroyTarget;
-} GHOST_DATA;
-
 static GHOST_DATA *
 Ghost_GetData(HWND hwnd)
 {
@@ -188,9 +181,9 @@ Ghost_OnCreate(HWND hwnd, CREATESTRUCTW *lpcs)
 
     // get the target
     hwndTarget = (HWND)lpcs->lpCreateParams;
-    if (!IsWindowVisible(hwndTarget) ||     // invisible?
-        GetParent(hwndTarget) ||            // child?
-        !IsHungAppWindow(hwndTarget))       // not hung?
+    if (!IsWindowVisible(hwndTarget) ||                             // invisible?
+        (GetWindowLongPtrW(hwndTarget, GWL_STYLE) & WS_CHILD) ||    // child?
+        !IsHungAppWindow(hwndTarget))                               // not hung?
     {
         return FALSE;
     }