From f469acacecfd3d215ebe5dde79517c45b92aa730 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Tue, 11 Dec 2018 12:30:59 +0900 Subject: [PATCH] [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(-) create mode 100644 win32ss/include/ghostwnd.h diff --git a/win32ss/include/ghostwnd.h b/win32ss/include/ghostwnd.h new file mode 100644 index 00000000000..6907580c79b --- /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@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 c5b3e8308c7..0c41dc3208b 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 726fe8ff3d8..efbc5d2a647 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@gmail.com) */ #include +#include "ghostwnd.h" -BOOL FASTCALL IntGoGhost(PWND Window, BOOL bGo) +#define NDEBUG +#include + +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 c348bf14171..cd7b45ce5c3 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 0de5f3f2602..7564109c47d 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 ccc9a6c5280..0abc0648731 100644 --- a/win32ss/user/user32/controls/ghost.c +++ b/win32ss/user/user32/controls/ghost.c @@ -7,12 +7,12 @@ #include #include +#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; }