From: Akihiro Sagawa Subject: imm32, user32: Create and destroy the default IME window implicitly. (try 3) (resend) Message-Id: <20160524223244.327F.375B48EC@gmail.com> Date: Tue, 24 May 2016 22:33:47 +0900 Fix bug 34056. Try 3: - Update todo_wine handling. Try 2: - Another approach to maintain default IME windows --- no more using hooks. - Add an internal API to imm32 as thread_data is still there. - User32 keeps reference counter in TEB block and call the new API when creating/destroying a window. Signed-off-by: Akihiro Sagawa --- dlls/imm32/imm.c | 34 ++++++++++++++++++++++++++-------- dlls/imm32/imm32.spec | 1 + dlls/imm32/tests/imm32.c | 6 +++--- dlls/user32/misc.c | 4 +++- dlls/user32/user_private.h | 2 ++ dlls/user32/win.c | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 12 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 3c805dc..846b824 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1600,16 +1600,22 @@ BOOL WINAPI ImmGetConversionStatus( return TRUE; } -/*********************************************************************** - * ImmGetDefaultIMEWnd (IMM32.@) - */ -HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) +HWND WINAPI __wine_register_window(HWND hWnd) { HWND ret, new = NULL; IMMThreadData* thread_data = IMM_GetThreadData(hWnd); if (!thread_data) return NULL; - if (thread_data->hwndDefault == NULL && thread_data->threadID == GetCurrentThreadId()) + if (hWnd == NULL) + { + /* Destroy default IME window */ + ret = thread_data->hwndDefault; + LeaveCriticalSection(&threaddata_cs); + DestroyWindow(ret); + EnterCriticalSection(&threaddata_cs); + thread_data->hwndDefault = NULL; + } + else if (thread_data->hwndDefault == NULL) { /* Do not create the window inside of a critical section */ LeaveCriticalSection(&threaddata_cs); @@ -1626,12 +1632,24 @@ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) } ret = thread_data->hwndDefault; LeaveCriticalSection(&threaddata_cs); - TRACE("Default is %p\n",ret); + TRACE("Register %p\n", ret); /* Clean up an unused new window outside of the critical section */ if (new != NULL) - { DestroyWindow(new); - } + return ret; +} + +/*********************************************************************** + * ImmGetDefaultIMEWnd (IMM32.@) + */ +HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) +{ + HWND ret; + IMMThreadData* thread_data = IMM_GetThreadData(hWnd); + if (!thread_data) + return NULL; + ret = thread_data->hwndDefault; + LeaveCriticalSection(&threaddata_cs); TRACE("Default is %p\n",ret); return ret; } diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index 0bee92a..1cb3942 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -114,3 +114,4 @@ ################################################################ # Wine internal extensions @ stdcall __wine_get_ui_window(ptr) +@ stdcall __wine_register_window(ptr) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index bb27853..2f4a02b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -884,15 +884,15 @@ static DWORD WINAPI test_default_ime_window_cb(void *arg) CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); ime_wnd = get_ime_window(); - todo_wine ok(ime_wnd != NULL, "Expected IME window existence\n"); + ok(ime_wnd != NULL, "Expected IME window existence\n"); default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); - todo_wine ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd); + ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd); hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", WS_OVERLAPPEDWINDOW | visible, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); DestroyWindow(hwnd2); - todo_wine ok(IsWindow(ime_wnd) || broken(/* Vista */ !visible), "Expected IME window existence\n"); + ok(IsWindow(ime_wnd) || broken(/* Vista */ !visible), "Expected IME window existence\n"); DestroyWindow(hwnd1); ok(!IsWindow(ime_wnd), "Expected no IME windows\n"); return 1; diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 7b283cc..0d57d04 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -41,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); #define IMM_INIT_MAGIC 0x19650412 static HWND (WINAPI *imm_get_ui_window)(HKL); +HWND (WINAPI *imm_register_window)(HWND) = NULL; /* MSIME messages */ static UINT WM_MSIME_SERVICE; @@ -684,7 +685,8 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) /* this part is not compatible with native imm32.dll */ imm_get_ui_window = (void*)GetProcAddress(imm32, "__wine_get_ui_window"); - if (!imm_get_ui_window) + imm_register_window = (void*)GetProcAddress(imm32, "__wine_register_window"); + if (!imm_get_ui_window || !imm_register_window) FIXME("native imm32.dll not supported\n"); return TRUE; } diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index e4a2ed1..c8a79f1 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -189,11 +189,13 @@ struct user_thread_info HWND top_window; /* Desktop window */ HWND msg_window; /* HWND_MESSAGE parent window */ RAWINPUT *rawinput; + DWORD ime_win_refs; /* Reference count of IME window */ }; C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); extern INT global_key_state_counter DECLSPEC_HIDDEN; +extern HWND (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; struct user_key_state_info { diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 8474e2d..46483ea 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -925,6 +925,22 @@ other_process: } +static BOOL needs_ime_window( HWND hwnd ) +{ + static const WCHAR ime_classW[] = {'I','M','E',0}; + WCHAR classW[8]; + + if (!GetSystemMetrics( SM_IMMENABLED ) && !GetSystemMetrics( SM_DBCSENABLED )) + return FALSE; + if (GetClassNameW( hwnd, classW, sizeof(classW)/sizeof(classW[0]) ) && + !strcmpW( classW, ime_classW )) + return FALSE; + if (GetClassLongPtrW( hwnd, GCL_STYLE ) & CS_IME) return FALSE; + + return TRUE; +} + + /*********************************************************************** * WIN_DestroyWindow * @@ -940,6 +956,16 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) TRACE("%p\n", hwnd ); + /* destroy default IME window */ + if (imm_register_window && needs_ime_window( hwnd )) + { + struct user_thread_info *thread_info = get_user_thread_info(); + thread_info->ime_win_refs--; + TRACE("ime_win_refs=%u\n", thread_info->ime_win_refs); + if (thread_info->ime_win_refs == 0) + imm_register_window( NULL ); + } + /* free child windows */ if ((list = WIN_ListChildren( hwnd ))) { @@ -1595,6 +1621,20 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, goto failed; } + /* create default IME window */ + + if (imm_register_window && needs_ime_window( hwnd )) + { + struct user_thread_info *thread_info = get_user_thread_info(); + thread_info->ime_win_refs++; + TRACE("ime_win_refs=%u\n", thread_info->ime_win_refs); + if (thread_info->ime_win_refs == 1) + { + HWND win = imm_register_window( hwnd ); + TRACE("create ime window (hwnd=%p)\n", win); + } + } + /* send WM_NCCALCSIZE */ if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))