https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4bcf23d1ded3d2fc104ba9e85b88fb1a59150183

commit 4bcf23d1ded3d2fc104ba9e85b88fb1a59150183
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Wed Apr 20 16:10:06 2022 +0900
Commit:     GitHub <[email protected]>
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 */

Reply via email to