https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4bcf23d1ded3d2fc104ba…
commit 4bcf23d1ded3d2fc104ba9e85b88fb1a59150183
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Apr 20 16:10:06 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Apr 20 16:10:06 2022 +0900
[NTUSER] Destroy the default IME window (#4462)
- Add IntFindNonImeRelatedWndOfSameThread, IntImeCanDestroyDefIMEforChild, and
IntImeCanDestroyDefIME helper functions.
- Do assignment unlock spwndDefaultIme at co_UserFreeWindow.
- Destroy the default IME window of the specified window if necessary at
co_UserDestroyWindow.
CORE-11700
---
win32ss/user/ntuser/ime.c | 197 +++++++++++++++++++++++++++++++++++++++++--
win32ss/user/ntuser/window.c | 21 ++++-
win32ss/user/ntuser/window.h | 13 +++
3 files changed, 221 insertions(+), 10 deletions(-)
diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c
index d7377c32f0b..e869608724f 100644
--- a/win32ss/user/ntuser/ime.c
+++ b/win32ss/user/ntuser/ime.c
@@ -21,15 +21,6 @@ DBG_DEFAULT_CHANNEL(UserMisc);
#define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE,
SUBLANG_CHINESE_TRADITIONAL)
#define LANGID_NEUTRAL MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
-// The IME-like windows are the IME windows and the IME UI windows.
-// The IME window's class name is "IME".
-// The IME UI window behaves the User Interface of IME for the user.
-#define IS_WND_IMELIKE(pwnd) \
- (((pwnd)->pcls->style & CS_IME) || \
- ((pwnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
-#define IS_WND_MENU(pWnd) \
- ((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU])
-
// The special virtual keys for Japanese: Used for key states.
//
https://www.kthree.co.jp/kihelp/index.html?page=app/vkey&type=html
#define VK_DBE_ALPHANUMERIC 0xF0
@@ -1820,4 +1811,192 @@ Quit:
return ret;
}
+// Searchs a non-IME-related window of the same thread of pwndTarget,
+// other than pwndTarget, around pwndParent. Returns TRUE if found.
+//
+// Win: IsChildSameThread
+BOOL IntFindNonImeRelatedWndOfSameThread(PWND pwndParent, PWND pwndTarget)
+{
+ PWND pwnd, pwndOwner, pwndNode;
+ PTHREADINFO ptiTarget = pwndTarget->head.pti;
+
+ // For all the children of pwndParent, ...
+ for (pwnd = pwndParent->spwndChild; pwnd; pwnd = pwnd->spwndNext)
+ {
+ if (pwnd == pwndTarget || pwnd->head.pti != ptiTarget || IS_WND_MENU(pwnd))
+ continue;
+
+ if (!IS_WND_CHILD(pwnd))
+ {
+ // Check if any IME-like owner.
+ BOOL bFound1 = FALSE;
+ for (pwndOwner = pwnd; pwndOwner; pwndOwner = pwndOwner->spwndOwner)
+ {
+ if (IS_WND_IMELIKE(pwndOwner))
+ {
+ bFound1 = TRUE;
+ break;
+ }
+ }
+ if (bFound1)
+ continue; // Skip if any IME-like owner.
+ }
+
+ pwndNode = pwnd;
+
+ if (IS_WND_CHILD(pwndNode))
+ {
+ // Check if any same-thread IME-like ancestor.
+ BOOL bFound2 = FALSE;
+ for (; IS_WND_CHILD(pwndNode); pwndNode = pwndNode->spwndParent)
+ {
+ if (pwndNode->head.pti != ptiTarget)
+ break;
+
+ if (IS_WND_IMELIKE(pwndNode))
+ {
+ bFound2 = TRUE;
+ break;
+ }
+ }
+ if (bFound2)
+ continue;
+ // Now, pwndNode is non-child or non-same-thread window.
+ }
+
+ if (!IS_WND_CHILD(pwndNode)) // pwndNode is non-child
+ {
+ // Check if any same-thread IME-like owner.
+ BOOL bFound3 = FALSE;
+ for (; pwndNode; pwndNode = pwndNode->spwndOwner)
+ {
+ if (pwndNode->head.pti != ptiTarget)
+ break;
+
+ if (IS_WND_IMELIKE(pwndNode))
+ {
+ bFound3 = TRUE;
+ break;
+ }
+ }
+ if (bFound3)
+ continue;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Can we destroy the default IME window for the target child window?
+// Win: ImeCanDestroyDefIMEforChild
+BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget)
+{
+ PWND pwndNode;
+ PIMEUI pimeui;
+ IMEUI SafeImeUI;
+
+ pimeui = ((PIMEWND)pImeWnd)->pimeui;
+ if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1)
+ return FALSE;
+
+ // Check IMEUI.fChildThreadDef
+ _SEH2_TRY
+ {
+ ProbeForRead(pimeui, sizeof(IMEUI), 1);
+ SafeImeUI = *pimeui;
+ if (!SafeImeUI.fChildThreadDef)
+ return FALSE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ;
+ }
+ _SEH2_END;
+
+ // The parent of pwndTarget is NULL or of the same thread of pwndTarget?
+ if (pwndTarget->spwndParent == NULL ||
+ pwndTarget->head.pti == pwndTarget->spwndParent->head.pti)
+ {
+ return FALSE;
+ }
+
+ for (pwndNode = pwndTarget; pwndNode; pwndNode = pwndNode->spwndParent)
+ {
+ if (pwndNode == pwndNode->head.rpdesk->pDeskInfo->spwnd)
+ break;
+
+ if (IntFindNonImeRelatedWndOfSameThread(pwndNode->spwndParent, pwndTarget))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Can we destroy the default IME window for the non-child target window?
+// If so, this function sets spwndOwner to NULL.
+// Win: ImeCanDestroyDefIME
+BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget)
+{
+ PWND pwndNode;
+ PIMEUI pimeui;
+ IMEUI SafeImeUI;
+
+ pimeui = ((PIMEWND)pImeWnd)->pimeui;
+ if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1)
+ return FALSE;
+
+ // Check IMEUI.fDestroy
+ _SEH2_TRY
+ {
+ ProbeForRead(pimeui, sizeof(IMEUI), 1);
+ SafeImeUI = *pimeui;
+ if (SafeImeUI.fDestroy)
+ return FALSE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ;
+ }
+ _SEH2_END;
+
+ // Any ancestor of pImeWnd is pwndTarget?
+ if (pImeWnd->spwndOwner)
+ {
+ for (pwndNode = pImeWnd->spwndOwner; pwndNode; pwndNode =
pwndNode->spwndOwner)
+ {
+ if (pwndNode == pwndTarget)
+ break;
+ }
+
+ if (!pwndNode)
+ return FALSE;
+ }
+
+ // Any ancestor of pwndTarget is IME-like?
+ for (pwndNode = pwndTarget; pwndNode; pwndNode = pwndNode->spwndOwner)
+ {
+ if (IS_WND_IMELIKE(pwndNode))
+ return FALSE;
+ }
+
+ // Adjust the ordering and top-mode status
+ IntImeSetFutureOwner(pImeWnd, pwndTarget);
+ for (pwndNode = pImeWnd->spwndOwner; pwndNode; pwndNode = pwndNode->spwndNext)
+ {
+ if (pwndNode == pImeWnd)
+ break;
+ }
+ if (pwndNode == pImeWnd)
+ IntImeCheckTopmost(pImeWnd);
+
+ // Is the owner of pImeWnd NULL or pwndTarget?
+ if (pImeWnd->spwndOwner && pwndTarget != pImeWnd->spwndOwner)
+ return FALSE;
+
+ pImeWnd->spwndOwner = NULL;
+ return TRUE;
+}
+
/* EOF */
diff --git a/win32ss/user/ntuser/window.c b/win32ss/user/ntuser/window.c
index da8da6cf68e..9ec554b4a24 100644
--- a/win32ss/user/ntuser/window.c
+++ b/win32ss/user/ntuser/window.c
@@ -658,6 +658,9 @@ LRESULT co_UserFreeWindow(PWND Window,
ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
}
+ if (IS_IMM_MODE() && Window == ThreadData->spwndDefaultIme)
+ UserAssignmentUnlock((PVOID*)&(ThreadData->spwndDefaultIme));
+
/* Fixes dialog test_focus breakage due to r66237. */
if (ThreadData->MessageQueue->spwndFocus == Window)
ThreadData->MessageQueue->spwndFocus = NULL;
@@ -2762,7 +2765,7 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
/* Check for owner thread */
- if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
+ if (Window->head.pti != ti)
{
/* Check if we are destroying the desktop window */
if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window
== Window->head.rpdesk->pDeskInfo->spwnd))
@@ -2918,6 +2921,22 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
/* Send destroy messages */
IntSendDestroyMsg(UserHMGetHandle(Window));
+ // Destroy the default IME window if necessary
+ if (IS_IMM_MODE() && !(ti->TIF_flags & TIF_INCLEANUP) &&
+ ti->spwndDefaultIme && !IS_WND_IMELIKE(Window) &&
!(Window->state & WNDS_DESTROYED))
+ {
+ if (IS_WND_CHILD(Window))
+ {
+ if (IntImeCanDestroyDefIMEforChild(ti->spwndDefaultIme, Window))
+ co_UserDestroyWindow(ti->spwndDefaultIme);
+ }
+ else
+ {
+ if (IntImeCanDestroyDefIME(ti->spwndDefaultIme, Window))
+ co_UserDestroyWindow(ti->spwndDefaultIme);
+ }
+ }
+
if (!IntIsWindow(UserHMGetHandle(Window)))
{
return TRUE;
diff --git a/win32ss/user/ntuser/window.h b/win32ss/user/ntuser/window.h
index 7086af36fc5..86daff24d97 100644
--- a/win32ss/user/ntuser/window.h
+++ b/win32ss/user/ntuser/window.h
@@ -102,4 +102,17 @@ VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget);
/* Undocumented dwFlags for IntBuildHwndList */
#define IACE_LIST 0x0002
+#define IS_WND_CHILD(pWnd) ((pWnd)->style & WS_CHILD)
+#define IS_WND_MENU(pWnd) ((pWnd)->pcls->atomClassName ==
gpsi->atomSysClass[ICLS_MENU])
+
+// The IME-like windows are the IME windows and the IME UI windows.
+// The IME window's class name is "IME".
+// The IME UI window behaves the User Interface of IME for the user.
+#define IS_WND_IMELIKE(pWnd) \
+ (((pWnd)->pcls->style & CS_IME) || \
+ ((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
+
+BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget);
+BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget);
+
/* EOF */