[NTUSER][USER32] Fix IME UI exception (#8227)

Fix BSoD when toggling visibility of the IME status
window (IME Toolbar).
JIRA issue: CORE-20261
- Add IntGetImeUIFromWnd helper function.
- Fix exception in IntNotifyImeShowStatus function.
- Fix initialization of IME UI in ImeWndProc_common
  function.
- Delete RegisterIMEClass function.
This commit is contained in:
Katayama Hirofumi MZ
2025-07-09 08:16:26 +09:00
committed by GitHub
parent 38d07d3a24
commit e7358c5930
5 changed files with 63 additions and 51 deletions

View File

@@ -1235,13 +1235,17 @@ typedef struct tagIMEUI
DWORD dwLastStatus;
} IMEUI, *PIMEUI;
/* Window Extra data container. */
typedef struct _IMEWND
typedef struct tagIMEWND
{
WND wnd;
PIMEUI pimeui;
} IMEWND, *PIMEWND;
#define GWLP_IMEWND_PIMEUI 0
/* IMEWND and GWLP_IMEWND_PIMEUI assume this alignment */
C_ASSERT(sizeof(WND) % sizeof(PVOID) == 0);
DWORD
NTAPI
NtUserAssociateInputContext(

View File

@@ -40,6 +40,13 @@ typedef struct tagIMEHOTKEY
PIMEHOTKEY gpImeHotKeyList = NULL;
LCID glcidSystem = 0;
static inline PIMEUI FASTCALL IntGetImeUIFromWnd(_In_ PWND pWnd)
{
ASSERT(pWnd->cbwndExtra >= sizeof(PIMEUI));
PIMEWND pImeWnd = (PIMEWND)pWnd;
return pImeWnd->pimeui;
}
static DWORD FASTCALL
IntGetImeCompatFlags(_In_opt_ PTHREADINFO pti)
{
@@ -2089,10 +2096,11 @@ co_IntCreateDefaultImeWindow(
pImeWnd = co_UserCreateWindowEx(&Cs, &ClassName, (PLARGE_STRING)&WindowName, NULL, WINVER);
if (pImeWnd)
{
pimeui = ((PIMEWND)pImeWnd)->pimeui;
pimeui = IntGetImeUIFromWnd(pImeWnd);
ASSERT(pimeui);
_SEH2_TRY
{
ProbeForWrite(pimeui, sizeof(IMEUI), 1);
ProbeForWrite(pimeui, sizeof(*pimeui), 1);
pimeui->fDefault = TRUE;
if (IS_WND_CHILD(pwndTarget) && pwndTarget->spwndParent->head.pti != pti)
pimeui->fChildThreadDef = TRUE;
@@ -2118,8 +2126,8 @@ IntImeCanDestroyDefIMEforChild(
PIMEUI pimeui;
IMEUI SafeImeUI;
pimeui = ((PIMEWND)pImeWnd)->pimeui;
if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1)
pimeui = IntGetImeUIFromWnd(pImeWnd);
if (!pimeui)
return FALSE;
// Check IMEUI.fChildThreadDef
@@ -2165,8 +2173,8 @@ IntImeCanDestroyDefIME(
PIMEUI pimeui;
IMEUI SafeImeUI;
pimeui = ((PIMEWND)pImeWnd)->pimeui;
if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1)
pimeui = IntGetImeUIFromWnd(pImeWnd);
if (!pimeui)
return FALSE;
// Check IMEUI.fDestroy
@@ -2257,8 +2265,8 @@ IntCheckImeShowStatus(
continue;
}
pimeui = ((PIMEWND)pwndNode)->pimeui;
if (!pimeui || pimeui == (PIMEUI)-1)
pimeui = IntGetImeUIFromWnd(pwndNode);
if (!pimeui)
continue;
if (pti && pti != pwndNode->head.pti)
@@ -2425,7 +2433,7 @@ IntSendOpenStatusNotify(PTHREADINFO ptiIME, PIMEUI pimeui, PWND pWnd, BOOL bOpen
}
}
// Update the IME status and send a notification.
// Update the IME toolbar visibility and send a notification
VOID FASTCALL
IntNotifyImeShowStatus(_In_ PWND pImeWnd)
{
@@ -2441,6 +2449,13 @@ IntNotifyImeShowStatus(_In_ PWND pImeWnd)
pti = PsGetCurrentThreadWin32Thread();
ptiIME = pImeWnd->head.pti;
pimeui = IntGetImeUIFromWnd(pImeWnd);
if (!pimeui)
{
ERR("Invalid IMEWND %p\n", pImeWnd);
return;
}
// Attach to the process if necessary
if (pti != ptiIME)
KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb));
@@ -2448,8 +2463,7 @@ IntNotifyImeShowStatus(_In_ PWND pImeWnd)
// Get an IMEUI and check whether hwndIMC is valid and update fShowStatus
_SEH2_TRY
{
ProbeForWrite(pImeWnd, sizeof(IMEWND), 1);
pimeui = ((PIMEWND)pImeWnd)->pimeui;
ProbeForWrite(pimeui, sizeof(*pimeui), 1);
SafeImeUI = *pimeui;
bShow = (gfIMEShowStatus == TRUE) && SafeImeUI.fCtrlShowStatus;
@@ -2466,7 +2480,7 @@ IntNotifyImeShowStatus(_In_ PWND pImeWnd)
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Exception in IntNotifyImeShowStatus: %p, %p, %p, %d, %d\n",
ERR("Exception in IntNotifyImeShowStatus: %p, %p, %p, %d, %d\n",
pImeWnd, pimeui, ptiIME, SafeImeUI.fCtrlShowStatus, gfIMEShowStatus);
if (pti != ptiIME)

View File

@@ -65,6 +65,7 @@ static const struct
/* { &ICONTITLE_builtin_class, FNID_ICONTITLE, ICLS_ICONTITLE}, // moved to win32k */
{ &STATIC_builtin_class, FNID_STATIC, ICLS_STATIC},
{ &GHOST_builtin_class, FNID_GHOST, ICLS_GHOST},
{ &IME_builtin_class, FNID_IME, ICLS_IME},
};
BOOL WINAPI RegisterSystemControls(VOID)
@@ -81,6 +82,12 @@ BOOL WINAPI RegisterSystemControls(VOID)
for (i = 0; i != sizeof(g_SysClasses) / sizeof(g_SysClasses[0]); i++)
{
if (g_SysClasses[i].fnid == FNID_IME)
{
if (!IS_IMM_MODE() || (RegisterDefaultClasses & ICLASS_TO_MASK(ICLS_IME)))
continue;
}
WndClass.lpszClassName = g_SysClasses[i].desc->name;
// Set Global bit!
@@ -99,12 +106,6 @@ BOOL WINAPI RegisterSystemControls(VOID)
RegisterDefaultClasses |= ICLASS_TO_MASK(g_SysClasses[i].ClsId);
}
if ( //gpsi->dwSRVIFlags & SRVINFO_IMM32 && Not supported yet, need NlsMbCodePageTag working in Win32k.
!(RegisterDefaultClasses & ICLASS_TO_MASK(ICLS_IME))) // So, work like XP.
{
RegisterIMEClass();
}
return TRUE;
}

View File

@@ -39,6 +39,7 @@ extern const struct builtin_class_descr MENU_builtin_class;
extern const struct builtin_class_descr SCROLL_builtin_class;
extern const struct builtin_class_descr STATIC_builtin_class;
extern const struct builtin_class_descr GHOST_builtin_class;
extern const struct builtin_class_descr IME_builtin_class;
ATOM WINAPI RegisterClassExWOWW(WNDCLASSEXW *,LPDWORD,WORD,DWORD,BOOL);
BOOL FASTCALL VersionRegisterClass(PCWSTR,LPCWSTR,HANDLE,HMODULE *);
@@ -46,4 +47,3 @@ BOOL FASTCALL VersionRegisterClass(PCWSTR,LPCWSTR,HANDLE,HMODULE *);
LRESULT WINAPI ImeWndProc_common(HWND,UINT,WPARAM,LPARAM,BOOL);
LRESULT WINAPI ImeWndProcA(HWND,UINT,WPARAM,LPARAM);
LRESULT WINAPI ImeWndProcW(HWND,UINT,WPARAM,LPARAM);
BOOL WINAPI RegisterIMEClass(VOID);

View File

@@ -1009,20 +1009,27 @@ ImeWndProc_common(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicod
return 0;
}
pimeui = (PIMEUI)GetWindowLongPtrW(hwnd, 0);
if (pimeui == NULL)
if (msg == WM_NCCREATE)
{
pimeui = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMEUI));
if (pimeui == NULL)
if (!pimeui)
{
ERR("HeapAlloc failed\n");
NtUserSetWindowFNID(hwnd, FNID_DESTROY);
DestroyWindow(hwnd);
return FALSE;
}
pimeui->spwnd = pWnd;
SetWindowLongPtrW(hwnd, GWLP_IMEWND_PIMEUI, (LONG_PTR)pimeui);
}
else
{
pimeui = (PIMEUI)GetWindowLongPtrW(hwnd, GWLP_IMEWND_PIMEUI);
if (!pimeui)
{
ERR("Invalid IMEWND\n");
NtUserSetWindowFNID(hwnd, FNID_DESTROY);
return 0;
}
SetWindowLongPtrW(hwnd, 0, (LONG_PTR)pimeui);
pimeui->spwnd = pWnd;
}
if (IS_CICERO_MODE())
@@ -1173,30 +1180,16 @@ BOOL WINAPI UpdatePerUserImmEnabling(VOID)
return ret;
}
BOOL
WINAPI
RegisterIMEClass(VOID)
const struct builtin_class_descr IME_builtin_class =
{
ATOM atom;
WNDCLASSEXW WndClass = { sizeof(WndClass) };
WndClass.lpszClassName = L"IME";
WndClass.style = CS_GLOBALCLASS;
WndClass.lpfnWndProc = ImeWndProcW;
WndClass.cbWndExtra = sizeof(LONG_PTR);
WndClass.hCursor = LoadCursorW(NULL, IDC_ARROW);
atom = RegisterClassExWOWW(&WndClass, 0, FNID_IME, 0, FALSE);
if (!atom)
{
ERR("Failed to register IME Class!\n");
return FALSE;
}
RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME);
TRACE("RegisterIMEClass atom = %u\n", atom);
return TRUE;
}
L"IME", /* name */
CS_GLOBALCLASS, /* style */
ImeWndProcA, /* procA */
ImeWndProcW, /* procW */
sizeof(IMEWND) - sizeof(WND), /* extra */
IDC_ARROW, /* cursor */
NULL /* brush */
};
/*
* @implemented