[WIN32SS][USER32] Add Ghost codes (retrial of #1100) (#1112)

CORE-11944
This commit is contained in:
Katayama Hirofumi MZ 2018-12-11 12:30:59 +09:00 committed by GitHub
parent 99b055a506
commit f469acacec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 199 additions and 21 deletions

View file

@ -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

View 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 */

View file

@ -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 <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;
}

View file

@ -1 +1 @@
BOOL FASTCALL IntGoGhost(PWND Window, BOOL bGo);
BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung);

View 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

View 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;
}