https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f469acacecfd3d215ebe5…
commit f469acacecfd3d215ebe5dde79517c45b92aa730
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Dec 11 12:30:59 2018 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Dec 11 12:30:59 2018 +0900
[WIN32SS][USER32] Add Ghost codes (retrial of #1100) (#1112)
CORE-11944
---
win32ss/include/ghostwnd.h | 20 +++++
win32ss/user/ntuser/class.h | 8 ++
win32ss/user/ntuser/ghost.c | 167 +++++++++++++++++++++++++++++++++--
win32ss/user/ntuser/ghost.h | 2 +-
win32ss/user/ntuser/message.c | 8 +-
win32ss/user/user32/controls/ghost.c | 15 +---
6 files changed, 199 insertions(+), 21 deletions(-)
diff --git a/win32ss/include/ghostwnd.h b/win32ss/include/ghostwnd.h
new file mode 100644
index 0000000000..6907580c79
--- /dev/null
+++ b/win32ss/include/ghostwnd.h
@@ -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(a)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
diff --git a/win32ss/user/ntuser/class.h b/win32ss/user/ntuser/class.h
index c5b3e8308c..0c41dc3208 100644
--- a/win32ss/user/ntuser/class.h
+++ b/win32ss/user/ntuser/class.h
@@ -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 */
diff --git a/win32ss/user/ntuser/ghost.c b/win32ss/user/ntuser/ghost.c
index 726fe8ff3d..efbc5d2a64 100644
--- a/win32ss/user/ntuser/ghost.c
+++ b/win32ss/user/ntuser/ghost.c
@@ -1,23 +1,178 @@
/*
* 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(a)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;
}
diff --git a/win32ss/user/ntuser/ghost.h b/win32ss/user/ntuser/ghost.h
index c348bf1417..cd7b45ce5c 100644
--- a/win32ss/user/ntuser/ghost.h
+++ b/win32ss/user/ntuser/ghost.h
@@ -1 +1 @@
-BOOL FASTCALL IntGoGhost(PWND Window, BOOL bGo);
+BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung);
diff --git a/win32ss/user/ntuser/message.c b/win32ss/user/ntuser/message.c
index 0de5f3f260..7564109c47 100644
--- a/win32ss/user/ntuser/message.c
+++ b/win32ss/user/ntuser/message.c
@@ -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
diff --git a/win32ss/user/user32/controls/ghost.c b/win32ss/user/user32/controls/ghost.c
index ccc9a6c528..0abc064873 100644
--- a/win32ss/user/user32/controls/ghost.c
+++ b/win32ss/user/user32/controls/ghost.c
@@ -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;
}