diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 023d816a51e..1230c2e2b95 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -992,18 +992,58 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) return FALSE; } +static HWND imm_detach_default_window(IMMThreadData *thread_data) +{ + HWND to_destroy; + + imm_couninit_thread(thread_data, TRUE); + to_destroy = thread_data->hwndDefault; + thread_data->hwndDefault = NULL; + thread_data->windowRefs = 0; + return to_destroy; +} + /*********************************************************************** * ImmDisableIME (IMM32.@) */ BOOL WINAPI ImmDisableIME(DWORD idThread) { + IMMThreadData *thread_data; + HWND to_destroy; + if (idThread == (DWORD)-1) + { disable_ime = TRUE; - else { - IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread); + + while (1) + { + to_destroy = 0; + EnterCriticalSection(&threaddata_cs); + LIST_FOR_EACH_ENTRY(thread_data, &ImmThreadDataList, IMMThreadData, entry) + { + if (thread_data->hwndDefault) + { + to_destroy = imm_detach_default_window(thread_data); + break; + } + } + LeaveCriticalSection(&threaddata_cs); + + if (!to_destroy) + break; + DestroyWindow(to_destroy); + } + } + else + { + thread_data = IMM_GetThreadData(NULL, idThread); if (!thread_data) return FALSE; thread_data->disableIME = TRUE; + to_destroy = imm_detach_default_window(thread_data); LeaveCriticalSection(&threaddata_cs); + + if (to_destroy) + DestroyWindow(to_destroy); } return TRUE; } @@ -1878,11 +1918,7 @@ void WINAPI __wine_unregister_window(HWND hwnd) /* Destroy default IME window */ if (thread_data->windowRefs == 0) - { - imm_couninit_thread(thread_data, TRUE); - to_destroy = thread_data->hwndDefault; - thread_data->hwndDefault = NULL; - } + to_destroy = imm_detach_default_window(thread_data); LeaveCriticalSection(&threaddata_cs); if (to_destroy) DestroyWindow( to_destroy ); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 759b564aba9..9e0e59d384d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2241,6 +2241,57 @@ static void test_com_initialization(void) test_apttype(-1); } +static DWORD WINAPI disable_ime_thread(void *arg) +{ + HWND h, def; + MSG msg; + BOOL r; + + h = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(h != NULL, "CreateWindow failed\n"); + def = ImmGetDefaultIMEWnd(h); + ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); + + r = ImmDisableIME(arg ? GetCurrentThreadId() : 0); + ok(r, "ImmDisableIME failed\n"); + + if (arg) + { + def = ImmGetDefaultIMEWnd(h); + todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); + while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + } + def = ImmGetDefaultIMEWnd(h); + ok(!def, "ImmGetDefaultIMEWnd returned %p\n", def); + return 0; +} + +static void test_ImmDisableIME(void) +{ + HANDLE thread; + HWND def; + BOOL r; + + def = ImmGetDefaultIMEWnd(hwnd); + ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n"); + + thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + thread = CreateThread(NULL, 0, disable_ime_thread, (void*)1, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + r = ImmDisableIME(-1); + ok(r, "ImmDisableIME(-1) failed\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); +} + START_TEST(imm32) { if (!is_ime_enabled()) { @@ -2276,6 +2327,9 @@ START_TEST(imm32) { if (pSendInput) test_ime_processkey(); else win_skip("SendInput is not available\n"); + + /* there's no way of enabling IME - keep the test last */ + test_ImmDisableIME(); } cleanup(); }