From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 540 ++++++++++++++++++++++----------------- 1 file changed, 308 insertions(+), 232 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 71d6b6ec64d..bd6ac479c38 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -986,256 +986,332 @@ static void test_NtUserAssociateInputContext(void) ImmReleaseContext(hwnd,imc); }
-typedef struct _igc_threadinfo { +struct test_cross_thread_himc_params +{ HWND hwnd; HANDLE event; - HIMC himc; - HIMC u_himc; -} igc_threadinfo; - + HIMC himc[2]; + INPUTCONTEXT *contexts[2]; +};
-static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam) +static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) { - HIMC h1,h2; - HWND hwnd2; - COMPOSITIONFORM cf; - CANDIDATEFORM cdf; - POINT pt; + struct test_cross_thread_himc_params *params = arg; + COMPOSITIONFORM composition = {0}; + CANDIDATEFORM candidate = {0}; + INPUTCONTEXT *contexts[2]; + HIMC himc[2], tmp_himc; + HWND hwnd, tmp_hwnd; + POINT pos = {0}; MSG msg;
- igc_threadinfo *info= (igc_threadinfo*)lpParam; - info->hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); - - h1 = ImmGetContext(hwnd); - ok(info->himc == h1, "hwnd context changed in new thread\n"); - h2 = ImmGetContext(info->hwnd); - ok(h2 != h1, "new hwnd in new thread should have different context\n"); - info->himc = h2; - ImmReleaseContext(hwnd,h1); - - hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); - h1 = ImmGetContext(hwnd2); + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + himc[0] = ImmGetContext( hwnd ); + ok_ne( NULL, himc[0], HIMC, "%p" ); + contexts[0] = ImmLockIMC( himc[0] ); + ok_ne( NULL, contexts[0], INPUTCONTEXT *, "%p" ); + + tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + tmp_himc = ImmGetContext( tmp_hwnd ); + ok_eq( himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( tmp_hwnd, tmp_himc ) ); + ok_ret( 1, DestroyWindow( tmp_hwnd ) );
- ok(h1 == h2, "Windows in same thread should have same default context\n"); - ImmReleaseContext(hwnd2,h1); - ImmReleaseContext(info->hwnd,h2); - DestroyWindow(hwnd2); + himc[1] = ImmCreateContext(); + ok_ne( NULL, himc[1], HIMC, "%p" ); + contexts[1] = ImmLockIMC( himc[1] ); + ok_ne( NULL, contexts[1], INPUTCONTEXT *, "%p" ); + + ok_ret( 1, ImmSetOpenStatus( himc[0], 0xdeadbeef ) ); + ok_ret( 1, ImmSetOpenStatus( himc[1], 0xfeedcafe ) ); + ok_ret( 1, ImmSetCompositionWindow( himc[0], &composition ) ); + ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) ); + ok_ret( 1, ImmSetCandidateWindow( himc[0], &candidate ) ); + ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); + ok_ret( 1, ImmSetStatusWindowPos( himc[0], &pos ) ); + ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); + + params->hwnd = hwnd; + params->himc[0] = himc[0]; + params->himc[1] = himc[1]; + params->contexts[0] = contexts[0]; + params->contexts[1] = contexts[1]; + SetEvent( params->event ); + + while (GetMessageW( &msg, 0, 0, 0 )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + }
- /* priming for later tests */ - ImmSetCompositionWindow(h1, &cf); - ImmSetStatusWindowPos(h1, &pt); - info->u_himc = ImmCreateContext(); - ImmSetOpenStatus(info->u_himc, TRUE); - cdf.dwIndex = 0; - cdf.dwStyle = CFS_CANDIDATEPOS; - cdf.ptCurrentPos.x = 0; - cdf.ptCurrentPos.y = 0; - ImmSetCandidateWindow(info->u_himc, &cdf); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); + ok_ret( 1, ImmUnlockIMC( himc[1] ) );
- SetEvent(info->event); + ok_ret( 1, ImmDestroyContext( himc[1] ) ); + ok_ret( 1, ImmReleaseContext( hwnd, himc[0] ) ); + ok_ret( 0, DestroyWindow( hwnd ) );
- while(GetMessageW(&msg, 0, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } return 1; }
-static void test_ImmThreads(void) +static void test_cross_thread_himc(void) { - HIMC himc, otherHimc, h1; - igc_threadinfo threadinfo; - HANDLE hThread; - DWORD dwThreadId; - BOOL rc; - LOGFONTA lf; - COMPOSITIONFORM cf; - CANDIDATEFORM cdf; - DWORD status, sentence; - POINT pt; + static const WCHAR comp_string[] = L"CompString"; + struct test_cross_thread_himc_params params; + COMPOSITIONFORM composition = {0}; + DWORD tid, conversion, sentence; + CANDIDATEFORM candidate = {0}; + COMPOSITIONSTRING *string; + HIMC himc[2], tmp_himc; + INPUTCONTEXT *tmp_ctx; + LOGFONTW fontW = {0}; + LOGFONTA fontA = {0}; + char buffer[512]; + POINT pos = {0}; + HANDLE thread; + BYTE *dst;
- himc = ImmGetContext(hwnd); - threadinfo.event = CreateEventA(NULL, TRUE, FALSE, NULL); - threadinfo.himc = himc; - hThread = CreateThread(NULL, 0, ImmGetContextThreadFunc, &threadinfo, 0, &dwThreadId ); - WaitForSingleObject(threadinfo.event, INFINITE); + himc[0] = ImmGetContext( hwnd ); + ok_ne( NULL, himc[0], HIMC, "%p" ); + ok_ne( NULL, ImmLockIMC( himc[0] ), INPUTCONTEXT *, "%p" ); + ok_ret( 1, ImmUnlockIMC( himc[0] ) );
- otherHimc = ImmGetContext(threadinfo.hwnd); + params.event = CreateEventW(NULL, TRUE, FALSE, NULL); + ok_ne( NULL, params.event, HANDLE, "%p" ); + thread = CreateThread( NULL, 0, test_cross_thread_himc_thread, ¶ms, 0, &tid ); + ok_ne( NULL, thread, HANDLE, "%p" ); + WaitForSingleObject( params.event, INFINITE );
- ok(himc != otherHimc, "Windows from other threads should have different himc\n"); - ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n"); + tmp_himc = ImmGetContext( params.hwnd ); + ok_ne( himc[0], tmp_himc, HIMC, "%p" ); + ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( params.hwnd, tmp_himc ) );
- SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, TRUE); - SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, TRUE); - SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE); - rc = ImmSetActiveContext(hwnd, otherHimc, TRUE); - ok(rc, "ImmSetActiveContext failed\n"); - CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE); - SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); - rc = ImmSetActiveContext(hwnd, otherHimc, FALSE); - ok(rc, "ImmSetActiveContext failed\n"); - CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE); - SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, FALSE); - SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, FALSE); + himc[1] = ImmCreateContext(); + ok_ne( NULL, himc[1], HIMC, "%p" ); + tmp_ctx = ImmLockIMC( himc[1] ); + ok_ne( NULL, tmp_ctx, INPUTCONTEXT *, "%p" ); + + tmp_ctx->hCompStr = ImmReSizeIMCC( tmp_ctx->hCompStr, 512 ); + ok_ne( NULL, tmp_ctx->hCompStr, HIMCC, "%p" ); + string = ImmLockIMCC( tmp_ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + string->dwSize = sizeof(COMPOSITIONSTRING); + string->dwCompStrLen = wcslen( comp_string ); + string->dwCompStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompStrOffset; + memcpy( dst, comp_string, string->dwCompStrLen * sizeof(WCHAR) ); + string->dwSize += string->dwCompStrLen * sizeof(WCHAR); + + string->dwCompClauseLen = 2 * sizeof(DWORD); + string->dwCompClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = string->dwCompStrLen; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompAttrLen = string->dwCompStrLen; + string->dwCompAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompAttrOffset; + memset( dst, ATTR_INPUT, string->dwCompStrLen ); + string->dwSize += string->dwCompStrLen; + ok_ret( 0, ImmUnlockIMCC( tmp_ctx->hCompStr ) ); + + ok_ret( 1, ImmUnlockIMC( himc[1] ) ); + + /* ImmLockIMC should succeed with cross thread HIMC */ + + tmp_ctx = ImmLockIMC( params.himc[0] ); + ok_eq( params.contexts[0], tmp_ctx, INPUTCONTEXT *, "%p" ); + ok_ret( 2, ImmGetIMCLockCount( params.himc[0] ) ); + + tmp_ctx->hCompStr = ImmReSizeIMCC( tmp_ctx->hCompStr, 512 ); + ok_ne( NULL, tmp_ctx->hCompStr, HIMCC, "%p" ); + string = ImmLockIMCC( tmp_ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + string->dwSize = sizeof(COMPOSITIONSTRING); + string->dwCompStrLen = wcslen( comp_string ); + string->dwCompStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompStrOffset; + memcpy( dst, comp_string, string->dwCompStrLen * sizeof(WCHAR) ); + string->dwSize += string->dwCompStrLen * sizeof(WCHAR); + + string->dwCompClauseLen = 2 * sizeof(DWORD); + string->dwCompClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = string->dwCompStrLen; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompAttrLen = string->dwCompStrLen; + string->dwCompAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompAttrOffset; + memset( dst, ATTR_INPUT, string->dwCompStrLen ); + string->dwSize += string->dwCompStrLen; + ok_ret( 0, ImmUnlockIMCC( tmp_ctx->hCompStr ) ); + + ok_ret( 1, ImmUnlockIMC( params.himc[0] ) ); + + tmp_ctx = ImmLockIMC( params.himc[1] ); + ok_eq( params.contexts[1], tmp_ctx, INPUTCONTEXT *, "%p" ); + ok_ret( 2, ImmGetIMCLockCount( params.himc[1] ) ); + ok_ret( 1, ImmUnlockIMC( params.himc[1] ) ); + + /* ImmSetActiveContext should succeed with cross thread HIMC */ + + SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE, TRUE ); + SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE, TRUE ); + + SET_EXPECT( WM_IME_SETCONTEXT_ACTIVATE ); + ok_ret( 1, ImmSetActiveContext( hwnd, params.himc[0], TRUE ) ); + CHECK_CALLED( WM_IME_SETCONTEXT_ACTIVATE ); + + SET_EXPECT( WM_IME_SETCONTEXT_DEACTIVATE ); + ok_ret( 1, ImmSetActiveContext( hwnd, params.himc[0], FALSE ) ); + CHECK_CALLED( WM_IME_SETCONTEXT_DEACTIVATE ); + + SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE, FALSE ); + SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE, FALSE ); + + /* ImmSetOpenStatus should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetOpenStatus( himc[1], 0xdeadbeef ) ); + ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( himc[1] ) ); + + ok_ret( 0, ImmSetOpenStatus( params.himc[0], TRUE ) ); + ok_ret( 0, ImmSetOpenStatus( params.himc[1], TRUE ) ); + ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params.himc[0] ) ); + ok_ret( (int)0xfeedcafe, ImmGetOpenStatus( params.himc[1] ) ); + ok_ret( 0, ImmSetOpenStatus( params.himc[0], FALSE ) ); + ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params.himc[0] ) ); + + /* ImmSetConversionStatus should fail with cross thread HIMC */ + + ok_ret( 1, ImmGetConversionStatus( himc[1], &conversion, &sentence ) ); + ok_ret( 1, ImmSetConversionStatus( himc[1], conversion, sentence ) ); + + ok_ret( 1, ImmGetConversionStatus( params.himc[0], &conversion, &sentence ) ); + ok_ret( 1, ImmGetConversionStatus( params.himc[1], &conversion, &sentence ) ); + ok_ret( 0, ImmSetConversionStatus( params.himc[0], conversion, sentence ) ); + ok_ret( 0, ImmSetConversionStatus( params.himc[1], conversion, sentence ) ); + + /* ImmSetCompositionFont(W|A) should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetCompositionFontA( himc[1], &fontA ) ); + ok_ret( 1, ImmGetCompositionFontA( himc[1], &fontA ) ); + ok_ret( 1, ImmSetCompositionFontW( himc[1], &fontW ) ); + ok_ret( 1, ImmGetCompositionFontW( himc[1], &fontW ) ); + + ok_ret( 0, ImmSetCompositionFontA( params.himc[0], &fontA ) ); + ok_ret( 0, ImmSetCompositionFontA( params.himc[1], &fontA ) ); + ok_ret( 1, ImmGetCompositionFontA( params.himc[0], &fontA ) ); + ok_ret( 1, ImmGetCompositionFontA( params.himc[1], &fontA ) ); + ok_ret( 0, ImmSetCompositionFontW( params.himc[0], &fontW ) ); + ok_ret( 0, ImmSetCompositionFontW( params.himc[1], &fontW ) ); + ok_ret( 1, ImmGetCompositionFontW( params.himc[0], &fontW ) ); + ok_ret( 1, ImmGetCompositionFontW( params.himc[1], &fontW ) );
- h1 = ImmAssociateContext(hwnd,otherHimc); - ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n"); - h1 = ImmGetContext(hwnd); - ok(h1 == himc, "Context for window should remain unchanged\n"); - ImmReleaseContext(hwnd,h1); - - h1 = ImmAssociateContext(hwnd, threadinfo.u_himc); - ok (h1 == NULL, "Should fail to associate a context from a different thread\n"); - h1 = ImmGetContext(hwnd); - ok(h1 == himc, "Context for window should remain unchanged\n"); - ImmReleaseContext(hwnd,h1); - - h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc); - ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n"); - h1 = ImmGetContext(threadinfo.hwnd); - ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n"); - ImmReleaseContext(threadinfo.hwnd,h1); - - /* OpenStatus */ - rc = ImmSetOpenStatus(himc, TRUE); - ok(rc != 0, "ImmSetOpenStatus failed\n"); - rc = ImmGetOpenStatus(himc); - ok(rc != 0, "ImmGetOpenStatus failed\n"); - rc = ImmSetOpenStatus(himc, FALSE); - ok(rc != 0, "ImmSetOpenStatus failed\n"); - rc = ImmGetOpenStatus(himc); - ok(rc == 0, "ImmGetOpenStatus failed\n"); - - rc = ImmSetOpenStatus(otherHimc, TRUE); - ok(rc == 0, "ImmSetOpenStatus should fail\n"); - rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE); - ok(rc == 0, "ImmSetOpenStatus should fail\n"); - rc = ImmGetOpenStatus(otherHimc); - ok(rc == 0, "ImmGetOpenStatus failed\n"); - rc = ImmGetOpenStatus(threadinfo.u_himc); - ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n"); - rc = ImmSetOpenStatus(otherHimc, FALSE); - ok(rc == 0, "ImmSetOpenStatus should fail\n"); - rc = ImmGetOpenStatus(otherHimc); - ok(rc == 0, "ImmGetOpenStatus failed\n"); - - /* CompositionFont */ - rc = ImmGetCompositionFontA(himc, &lf); - ok(rc != 0, "ImmGetCompositionFont failed\n"); - rc = ImmSetCompositionFontA(himc, &lf); - ok(rc != 0, "ImmSetCompositionFont failed\n"); - - rc = ImmGetCompositionFontA(otherHimc, &lf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n"); - rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n"); - rc = ImmSetCompositionFontA(otherHimc, &lf); - ok(rc == 0, "ImmSetCompositionFont should fail\n"); - rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf); - ok(rc == 0, "ImmSetCompositionFont should fail\n"); - - /* CompositionString */ - rc = ImmSetCompositionStringA(himc, SCS_SETSTR, "a", 2, NULL, 0); - ok(rc, "failed.\n"); - rc = ImmSetCompositionStringA(otherHimc, SCS_SETSTR, "a", 2, NULL, 0); - ok(!rc, "should fail.\n"); - rc = ImmSetCompositionStringA(threadinfo.u_himc, SCS_SETSTR, "a", 2, NULL, 0); - ok(!rc, "should fail.\n"); - - /* CompositionWindow */ - rc = ImmSetCompositionWindow(himc, &cf); - ok(rc != 0, "ImmSetCompositionWindow failed\n"); - rc = ImmGetCompositionWindow(himc, &cf); - ok(rc != 0, "ImmGetCompositionWindow failed\n"); - - rc = ImmSetCompositionWindow(otherHimc, &cf); - ok(rc == 0, "ImmSetCompositionWindow should fail\n"); - rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf); - ok(rc == 0, "ImmSetCompositionWindow should fail\n"); - rc = ImmGetCompositionWindow(otherHimc, &cf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); - rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); - - /* ConversionStatus */ - rc = ImmGetConversionStatus(himc, &status, &sentence); - ok(rc != 0, "ImmGetConversionStatus failed\n"); - rc = ImmSetConversionStatus(himc, status, sentence); - ok(rc != 0, "ImmSetConversionStatus failed\n"); - - rc = ImmGetConversionStatus(otherHimc, &status, &sentence); - ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); - rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence); - ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); - rc = ImmSetConversionStatus(otherHimc, status, sentence); - ok(rc == 0, "ImmSetConversionStatus should fail\n"); - rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence); - ok(rc == 0, "ImmSetConversionStatus should fail\n"); - - /* StatusWindowPos */ - rc = ImmSetStatusWindowPos(himc, &pt); - ok(rc != 0, "ImmSetStatusWindowPos failed\n"); - rc = ImmGetStatusWindowPos(himc, &pt); - ok(rc != 0, "ImmGetStatusWindowPos failed\n"); - - rc = ImmSetStatusWindowPos(otherHimc, &pt); - ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); - rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt); - ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); - rc = ImmGetStatusWindowPos(otherHimc, &pt); - ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); - rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt); - ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); - - h1 = ImmAssociateContext(threadinfo.hwnd, NULL); - ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n"); - h1 = ImmGetContext(threadinfo.hwnd); - ok (h1 == NULL, "CrossThread window context should be NULL\n"); - h1 = ImmAssociateContext(threadinfo.hwnd, h1); - ok (h1 == NULL, "Resetting cross thread context should fail\n"); - h1 = ImmGetContext(threadinfo.hwnd); - ok (h1 == NULL, "CrossThread window context should still be NULL\n"); - - rc = ImmDestroyContext(threadinfo.u_himc); - ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n"); - - /* Candidate Window */ - rc = ImmGetCandidateWindow(himc, 0, &cdf); - ok (rc == 0, "ImmGetCandidateWindow should fail\n"); - cdf.dwIndex = 0; - cdf.dwStyle = CFS_CANDIDATEPOS; - cdf.ptCurrentPos.x = 0; - cdf.ptCurrentPos.y = 0; - rc = ImmSetCandidateWindow(himc, &cdf); - ok (rc == 1, "ImmSetCandidateWindow should succeed\n"); - rc = ImmGetCandidateWindow(himc, 0, &cdf); - ok (rc == 1, "ImmGetCandidateWindow should succeed\n"); - - rc = ImmGetCandidateWindow(otherHimc, 0, &cdf); - ok (rc == 0, "ImmGetCandidateWindow should fail\n"); - rc = ImmSetCandidateWindow(otherHimc, &cdf); - ok (rc == 0, "ImmSetCandidateWindow should fail\n"); - rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf); - ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n"); - rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf); - ok (rc == 0, "ImmSetCandidateWindow should fail\n"); - - ImmReleaseContext(threadinfo.hwnd,otherHimc); - ImmReleaseContext(hwnd,himc); - - SendMessageA(threadinfo.hwnd, WM_CLOSE, 0, 0); - rc = PostThreadMessageA(dwThreadId, WM_QUIT, 1, 0); - ok(rc == 1, "PostThreadMessage should succeed\n"); - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - - himc = ImmGetContext(GetDesktopWindow()); - ok(himc == NULL, "Should not be able to get himc from other process window\n"); + /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */ + + ok_ret( 10, ImmGetCompositionStringA( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 20, ImmGetCompositionStringW( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 1, ImmSetCompositionStringA( himc[1], SCS_SETSTR, "a", 2, NULL, 0 ) ); + ok_ret( 1, ImmSetCompositionStringW( himc[1], SCS_SETSTR, L"a", 4, NULL, 0 ) ); + + ok_ret( 0, ImmSetCompositionStringA( params.himc[0], SCS_SETSTR, "a", 2, NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringA( params.himc[1], SCS_SETSTR, "a", 2, NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringW( params.himc[0], SCS_SETSTR, L"a", 4, NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringW( params.himc[1], SCS_SETSTR, L"a", 4, NULL, 0 ) ); + ok_ret( 10, ImmGetCompositionStringA( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 0, ImmGetCompositionStringA( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 20, ImmGetCompositionStringW( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 0, ImmGetCompositionStringW( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + + /* ImmSetCompositionWindow should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) ); + ok_ret( 1, ImmGetCompositionWindow( himc[1], &composition ) ); + + ok_ret( 0, ImmSetCompositionWindow( params.himc[0], &composition ) ); + ok_ret( 0, ImmSetCompositionWindow( params.himc[1], &composition ) ); + ok_ret( 1, ImmGetCompositionWindow( params.himc[0], &composition ) ); + ok_ret( 1, ImmGetCompositionWindow( params.himc[1], &composition ) ); + + /* ImmSetCandidateWindow should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); + ok_ret( 1, ImmGetCandidateWindow( himc[1], 0, &candidate ) ); + + ok_ret( 0, ImmSetCandidateWindow( params.himc[0], &candidate ) ); + ok_ret( 0, ImmSetCandidateWindow( params.himc[1], &candidate ) ); + ok_ret( 1, ImmGetCandidateWindow( params.himc[0], 0, &candidate ) ); + ok_ret( 1, ImmGetCandidateWindow( params.himc[1], 0, &candidate ) ); + + /* ImmSetStatusWindowPos should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); + ok_ret( 1, ImmGetStatusWindowPos( himc[1], &pos ) ); + + ok_ret( 0, ImmSetStatusWindowPos( params.himc[0], &pos ) ); + ok_ret( 0, ImmSetStatusWindowPos( params.himc[1], &pos ) ); + ok_ret( 1, ImmGetStatusWindowPos( params.himc[0], &pos ) ); + ok_ret( 1, ImmGetStatusWindowPos( params.himc[1], &pos ) ); + + /* ImmGenerateMessage should fail with cross thread HIMC */ + + ok_ret( 1, ImmGenerateMessage( himc[1] ) ); + + todo_wine ok_ret( 0, ImmGenerateMessage( params.himc[0] ) ); + todo_wine ok_ret( 0, ImmGenerateMessage( params.himc[1] ) ); + + /* ImmAssociateContext should fail with cross thread HWND or HIMC */ + + tmp_himc = ImmAssociateContext( hwnd, params.himc[0] ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( hwnd ); + ok_eq( himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( hwnd, tmp_himc ) ); + + tmp_himc = ImmAssociateContext( hwnd, params.himc[1] ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( hwnd ); + ok_eq( himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( hwnd, tmp_himc ) ); + + tmp_himc = ImmAssociateContext( params.hwnd, params.himc[1] ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( params.hwnd ); + ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( params.hwnd, tmp_himc ) ); + + /* ImmAssociateContext should succeed with cross thread HWND and NULL HIMC */ + + tmp_himc = ImmAssociateContext( params.hwnd, NULL ); + ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( params.hwnd ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + + /* ImmReleaseContext / ImmDestroyContext should fail with cross thread HIMC */ + + ok_ret( 1, ImmReleaseContext( params.hwnd, params.himc[0] ) ); + ok_ret( 0, ImmDestroyContext( params.himc[1] ) ); + + /* ImmGetContext should fail with another process HWND */ + + tmp_himc = ImmGetContext( GetDesktopWindow() ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + + ok_ret( 0, SendMessageW( params.hwnd, WM_CLOSE, 0, 0 ) ); + ok_ret( 1, PostThreadMessageW( tid, WM_QUIT, 1, 0 ) ); + ok_ret( 0, WaitForSingleObject( thread, 5000 ) ); + ok_ret( 1, CloseHandle( thread ) ); + ok_ret( 1, CloseHandle( params.event ) ); + + ok_ret( 1, ImmReleaseContext( hwnd, himc[0] ) ); + ok_ret( 1, ImmDestroyContext( himc[1] ) ); }
static void test_ImmIsUIMessage(void) @@ -6031,7 +6107,7 @@ START_TEST(imm32) test_ImmIME(); test_ImmAssociateContextEx(); test_NtUserAssociateInputContext(); - test_ImmThreads(); + test_cross_thread_himc(); test_ImmIsUIMessage(); test_ImmGetContext(); test_ImmDefaultHwnd();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 25d1df47a1c..268d9142732 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -441,11 +441,14 @@ BOOL WINAPI ImmFreeLayout( HKL hkl )
EnterCriticalSection( &ime_cs ); if ((ime = find_ime_from_hkl( hkl )) && ime->refcount) ime = NULL; - if (ime) list_remove( &ime->entry ); + if (ime) + { + list_remove( &ime->entry ); + if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); + } LeaveCriticalSection( &ime_cs ); if (!ime) return TRUE;
- if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); FreeLibrary( ime->module ); free( ime ); return TRUE; @@ -460,12 +463,11 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) TRACE( "hkl %p\n", hkl );
EnterCriticalSection( &ime_cs ); - ime = find_ime_from_hkl( hkl ); - LeaveCriticalSection( &ime_cs ); - if (ime) return TRUE; - - if (!(ime = calloc( 1, sizeof(*ime) ))) return FALSE; - ime->hkl = hkl; + if ((ime = find_ime_from_hkl( hkl )) || !(ime = calloc( 1, sizeof(*ime) ))) + { + LeaveCriticalSection( &ime_cs ); + return !!ime; + }
if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) use_default_ime = TRUE; else if (!(ime->module = LoadLibraryW( buffer ))) use_default_ime = TRUE; @@ -481,6 +483,7 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \ !(ime->p##f = use_default_ime ? (void *)f : NULL)) \ { \ + LeaveCriticalSection( &ime_cs ); \ WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \ goto failed; \ } @@ -502,12 +505,16 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) LOAD_FUNCPTR( ImeGetImeMenuItems ); #undef LOAD_FUNCPTR
- if (!ime->pImeInquire( &ime->info, buffer, 0 )) goto failed; + ime->hkl = hkl; + if (!ime->pImeInquire( &ime->info, buffer, 0 )) + { + LeaveCriticalSection( &ime_cs ); + goto failed; + }
if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) );
- EnterCriticalSection( &ime_cs ); list_add_tail( &ime_list, &ime->entry ); LeaveCriticalSection( &ime_cs );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 268d9142732..753213b623f 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1919,20 +1919,18 @@ UINT WINAPI ImmGetIMEFileNameW( HKL hkl, WCHAR *buffer, UINT length ) /*********************************************************************** * ImmGetOpenStatus (IMM32.@) */ -BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) +BOOL WINAPI ImmGetOpenStatus( HIMC himc ) { - struct imc *data = get_imc_data( hIMC ); - static int i; + INPUTCONTEXT *ctx; + BOOL status;
- if (!data) - return FALSE; - - TRACE("(%p): semi-stub\n", hIMC); + TRACE( "himc %p\n", himc );
- if (!i++) - FIXME("(%p): semi-stub\n", hIMC); + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + status = ctx->fOpen; + ImmUnlockIMC( himc );
- return data->IMC.fOpen; + return status; }
/***********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 753213b623f..a17869a1c94 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2605,30 +2605,27 @@ BOOL WINAPI ImmSetConversionStatus( /*********************************************************************** * ImmSetOpenStatus (IMM32.@) */ -BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) +BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; HWND ui_hwnd;
- TRACE("%p %d\n", hIMC, fOpen); - - if (!data) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } + TRACE( "himc %p, status %u\n", himc, status );
- if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE;
- if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)hIMC ); + if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)himc );
- if (!fOpen != !data->IMC.fOpen) + if (!status != !ctx->fOpen) { - data->IMC.fOpen = fOpen; - ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS); - imc_notify_ime( data, IMN_SETOPENSTATUS, 0 ); + ctx->fOpen = status; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0 ); }
+ ImmUnlockIMC( himc ); + return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 89 ++++++++++++++++++++++++++++++++++++---- dlls/imm32/tests/imm32.c | 18 ++------ 2 files changed, 84 insertions(+), 23 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index a17869a1c94..81444ad420c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -39,6 +39,13 @@ UINT WM_MSIME_RECONVERT; UINT WM_MSIME_QUERYPOSITION; UINT WM_MSIME_DOCUMENTFEED;
+struct imc_entry +{ + HIMC himc; + INPUTCONTEXT context; + struct list entry; +}; + struct ime { LONG refcount; /* guarded by ime_cs */ @@ -49,6 +56,7 @@ struct ime
IMEINFO info; WCHAR ui_class[17]; + struct list input_contexts;
BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); @@ -435,16 +443,21 @@ static struct ime *find_ime_from_hkl( HKL hkl )
BOOL WINAPI ImmFreeLayout( HKL hkl ) { + struct imc_entry *imc_entry, *imc_next; struct ime *ime;
TRACE( "hkl %p\n", hkl );
EnterCriticalSection( &ime_cs ); - if ((ime = find_ime_from_hkl( hkl )) && ime->refcount) ime = NULL; - if (ime) + if ((ime = find_ime_from_hkl( hkl ))) { list_remove( &ime->entry ); if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); + LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry ) + { + ImmDestroyIMCC( imc_entry->context.hPrivate ); + free( imc_entry ); + } } LeaveCriticalSection( &ime_cs ); if (!ime) return TRUE; @@ -514,6 +527,7 @@ BOOL WINAPI ImmLoadIME( HKL hkl )
if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) ); + list_init( &ime->input_contexts );
list_add_tail( &ime_list, &ime->entry ); LeaveCriticalSection( &ime_cs ); @@ -562,13 +576,63 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); }
+static void ime_save_input_context( struct ime *ime, HIMC himc, INPUTCONTEXT *ctx ) +{ + static INPUTCONTEXT default_input_context = + { + .cfCandForm = {{.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}} + }; + const INPUTCONTEXT old = *ctx; + struct imc_entry *entry; + + *ctx = default_input_context; + ctx->hWnd = old.hWnd; + ctx->hMsgBuf = old.hMsgBuf; + ctx->hCompStr = old.hCompStr; + ctx->hCandInfo = old.hCandInfo; + ctx->hGuideLine = old.hGuideLine; + if (!(ctx->hPrivate = ImmCreateIMCC( ime->info.dwPrivateDataSize ))) + WARN( "Failed to allocate IME private data\n" ); + + if (!(entry = malloc( sizeof(*entry) ))) return; + entry->himc = himc; + entry->context = *ctx; + + EnterCriticalSection( &ime_cs ); + + /* reference the IME the first time the input context cache is used + * in the same way Windows does it, so it doesn't get destroyed and + * INPUTCONTEXT cache lost when keyboard layout is changed + */ + if (list_empty( &ime->input_contexts )) ime->refcount++; + + list_add_tail( &ime->input_contexts, &entry->entry ); + LeaveCriticalSection( &ime_cs ); +} + +static INPUTCONTEXT *ime_find_input_context( struct ime *ime, HIMC himc ) +{ + struct imc_entry *entry; + + EnterCriticalSection( &ime_cs ); + LIST_FOR_EACH_ENTRY( entry, &ime->input_contexts, struct imc_entry, entry ) + if (entry->himc == himc) break; + LeaveCriticalSection( &ime_cs ); + + if (&entry->entry == &ime->input_contexts) return NULL; + return &entry->context; +} + static void imc_release_ime( struct imc *imc, struct ime *ime ) { + INPUTCONTEXT *ctx; + if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); imc->ui_hwnd = NULL; ime->pImeSelect( imc->handle, FALSE ); + + if ((ctx = ime_find_input_context( ime, imc->handle ))) *ctx = imc->IMC; ime_release( ime ); - ImmDestroyIMCC( imc->IMC.hPrivate ); }
static struct ime *imc_select_ime( struct imc *imc ) @@ -587,10 +651,11 @@ static struct ime *imc_select_ime( struct imc *imc ) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else { - if (!(imc->IMC.hPrivate = ImmCreateIMCC( imc->ime->info.dwPrivateDataSize ))) - WARN( "Failed to allocate IME private data for IMC %p\n", imc ); - imc->IMC.fdwConversion = imc->ime->info.fdwConversionCaps; - imc->IMC.fdwSentence = imc->ime->info.fdwSentenceCaps; + INPUTCONTEXT *ctx; + + if ((ctx = ime_find_input_context( imc->ime, imc->handle ))) imc->IMC = *ctx; + else ime_save_input_context( imc->ime, imc->handle, &imc->IMC ); + imc->ime->pImeSelect( imc->handle, TRUE ); }
@@ -690,14 +755,20 @@ static void IMM_FreeThreadData(void)
static void IMM_FreeAllImmHkl(void) { - struct ime *ime, *next; + struct ime *ime, *ime_next;
- LIST_FOR_EACH_ENTRY_SAFE( ime, next, &ime_list, struct ime, entry ) + LIST_FOR_EACH_ENTRY_SAFE( ime, ime_next, &ime_list, struct ime, entry ) { + struct imc_entry *imc_entry, *imc_next; list_remove( &ime->entry );
ime->pImeDestroy( 1 ); FreeLibrary( ime->module ); + LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry ) + { + ImmDestroyIMCC( imc_entry->context.hPrivate ); + free( imc_entry ); + }
free( ime ); } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index bd6ac479c38..a4a06cb571b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4370,8 +4370,8 @@ static void test_ImmSetConversionStatus(void) todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( hkl ) ); - todo_wine ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); - todo_wine ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( old_hkl ) ); todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); @@ -4525,8 +4525,8 @@ static void test_ImmSetOpenStatus(void)
ok_ret( 1, ImmActivateLayout( old_hkl ) ); status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( old_status, status, UINT, "%#x" ); - todo_wine ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); + ok_eq( old_status, status, UINT, "%#x" ); + ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( hkl ) ); status = ImmGetOpenStatus( default_himc ); todo_wine ok_eq( 1, status, UINT, "%#x" ); @@ -4771,10 +4771,8 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( empty_sequence );
- todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_ret( 1, ImmActivateLayout( old_hkl ) ); ok_seq( deactivate_seq ); - todo_ImeDestroy = FALSE;
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -4810,9 +4808,7 @@ static void test_ImmActivateLayout(void) CHECK_CALLED( ImeInquire ); activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); - todo_ImeInquire = TRUE; ok_ret( 1, ImmLoadIME( hkl ) ); - todo_ImeInquire = FALSE;
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -4821,9 +4817,7 @@ static void test_ImmActivateLayout(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
- todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); - todo_ImeDestroy = FALSE; deactivate_with_window_seq[1].himc = himc; deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq ); @@ -4834,9 +4828,7 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence );
- todo_ImeInquire = TRUE; ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); - todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); @@ -4844,9 +4836,7 @@ static void test_ImmActivateLayout(void) ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) );
- todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); - todo_ImeDestroy = FALSE; ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 2 +- dlls/imm32/tests/imm32.c | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 81444ad420c..c99feb65a45 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2688,7 +2688,7 @@ BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status )
if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)himc );
- if (!status != !ctx->fOpen) + if (status != ctx->fOpen) { ctx->fOpen = status; ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS ); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a4a06cb571b..45d028ed387 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4418,7 +4418,6 @@ static void test_ImmSetOpenStatus(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, - .todo = TRUE, }, {0}, }; @@ -4427,17 +4426,14 @@ static void test_ImmSetOpenStatus(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, - .todo = TRUE, }, {0}, }; @@ -4502,8 +4498,8 @@ static void test_ImmSetOpenStatus(void) ok_seq( set_open_status_1_seq );
status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( 0xfeedcafe, status, UINT, "%#x" ); - todo_wine ok_eq( 0xfeedcafe, ctx->fOpen, UINT, "%#x" ); + ok_eq( 0xfeedcafe, status, UINT, "%#x" ); + ok_eq( 0xfeedcafe, ctx->fOpen, UINT, "%#x" );
ctx->hWnd = hwnd; ok_seq( empty_sequence ); @@ -4511,15 +4507,15 @@ static void test_ImmSetOpenStatus(void) ok_seq( set_open_status_2_seq );
status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( ~0, status, UINT, "%#x" ); - todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + ok_eq( ~0, status, UINT, "%#x" ); + ok_eq( ~0, ctx->fOpen, UINT, "%#x" );
ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) ); ok_seq( empty_sequence );
status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( ~0, status, UINT, "%#x" ); - todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + ok_eq( ~0, status, UINT, "%#x" ); + ok_eq( ~0, ctx->fOpen, UINT, "%#x" );
/* status is cached between IME activations */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c99feb65a45..b2dc58a95ab 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1844,20 +1844,16 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI /*********************************************************************** * ImmGetConversionStatus (IMM32.@) */ -BOOL WINAPI ImmGetConversionStatus( - HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) +BOOL WINAPI ImmGetConversionStatus( HIMC himc, DWORD *conversion, DWORD *sentence ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx;
- TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence); + TRACE( "himc %p, conversion %p, sentence %p\n", himc, conversion, sentence );
- if (!data) - return FALSE; - - if (lpfdwConversion) - *lpfdwConversion = data->IMC.fdwConversion; - if (lpfdwSentence) - *lpfdwSentence = data->IMC.fdwSentence; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if (conversion) *conversion = ctx->fdwConversion; + if (sentence) *sentence = ctx->fdwSentence; + ImmUnlockIMC( himc );
return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 41 +++++++++++++++++++--------------------- dlls/imm32/tests/imm32.c | 1 - 2 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b2dc58a95ab..d29684f34a2 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2635,37 +2635,34 @@ BOOL WINAPI ImmSetCompositionWindow( /*********************************************************************** * ImmSetConversionStatus (IMM32.@) */ -BOOL WINAPI ImmSetConversionStatus( - HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) +BOOL WINAPI ImmSetConversionStatus( HIMC himc, DWORD conversion, DWORD sentence ) { - DWORD oldConversion, oldSentence; - struct imc *data = get_imc_data( hIMC ); - - TRACE("%p %ld %ld\n", hIMC, fdwConversion, fdwSentence); + DWORD old_conversion, old_sentence; + INPUTCONTEXT *ctx;
- if (!data) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } + TRACE( "himc %p, conversion %#lx, sentence %#lx\n", himc, conversion, sentence );
- if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE;
- if ( fdwConversion != data->IMC.fdwConversion ) + if (conversion != ctx->fdwConversion) { - oldConversion = data->IMC.fdwConversion; - data->IMC.fdwConversion = fdwConversion; - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE); - imc_notify_ime( data, IMN_SETCONVERSIONMODE, 0 ); + old_conversion = ctx->fdwConversion; + ctx->fdwConversion = conversion; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_conversion, IMC_SETCONVERSIONMODE ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0 ); } - if ( fdwSentence != data->IMC.fdwSentence ) + + if (sentence != ctx->fdwSentence) { - oldSentence = data->IMC.fdwSentence; - data->IMC.fdwSentence = fdwSentence; - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE); - imc_notify_ime( data, IMN_SETSENTENCEMODE, 0 ); + old_sentence = ctx->fdwSentence; + ctx->fdwSentence = sentence; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_sentence, IMC_SETSENTENCEMODE ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0 ); }
+ ImmUnlockIMC( himc ); + return TRUE; }
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 45d028ed387..a6b43727f9e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4238,7 +4238,6 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xdeadbeef, .value = IMC_SETCONVERSIONMODE}, }, - {.todo = TRUE}, /* spurious calls */ {0}, }; const struct ime_call set_conversion_status_2_seq[] =
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131738
Your paranoid android.
=== w1064v1809 (32 bit report) ===
imm32: imm32.c:5031: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:5031: Test failed: 1 (missing): hkl E020047F, himc 000200D5, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:4589: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_PROCESS_KEY vkey 0x41, key_data 0 imm32.c:5220: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5223: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5225: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5232: Test failed: 4 (missing): hkl E020047F, himc 00090113, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5235: Test failed: 0 (missing): hkl E020047F, himc 00090113, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5764: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5897: Test failed: unicode: 0: ImmGetCompositionStringW returned 2, error 0 imm32.c:5900: Test failed: unicode: 0: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5911: Test failed: unicode: 0: got buffer "R" imm32.c:5897: Test failed: unicode: 1: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 1: got buffer L"\cd00\cdcd\cdcd\cdcd" imm32.c:5897: Test failed: unicode: 3: ImmGetCompositionStringW returned 2, error 0 imm32.c:5901: Test failed: unicode: 3: got buffer L"C\cdcd\cdcd\cdcd" imm32.c:5912: Test failed: unicode: 3: got buffer "C" imm32.c:5897: Test failed: unicode: 4: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 4: got buffer L"\cd00\cdcd" imm32.c:5897: Test failed: unicode: 8: ImmGetCompositionStringW returned 2, error 0 imm32.c:5902: Test failed: unicode: 8: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5913: Test failed: unicode: 8: got buffer "R" imm32.c:5897: Test failed: unicode: 10: ImmGetCompositionStringW returned 2, error 0 imm32.c:5903: Test failed: unicode: 10: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5914: Test failed: unicode: 10: got buffer "R" imm32.c:5955: Test failed: unicode: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5764: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5955: Test failed: ansi: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 2: expected ImeSetCompositionString
=== w11pro64 (32 bit report) ===
imm32: imm32.c:4986: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5031: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:5031: Test failed: 1 (missing): hkl E020047F, himc 00070143, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:4578: Test failed: ImmLoadIME returned 0, error 126 imm32.c:4588: Test failed: got ret 0, error 0 imm32.c:4589: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_PROCESS_KEY vkey 0x41, key_data 0 imm32.c:5087: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5213: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5220: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5223: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5225: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5232: Test failed: 4 (missing): hkl E020047F, himc 000F02AF, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5235: Test failed: 0 (missing): hkl E020047F, himc 000F02AF, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5323: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5428: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5459: Test failed: unicode: ImmGetCandidateListW returned 40, error 0 imm32.c:5464: Test failed: unicode: ImmGetCandidateListW returned 40, error 0 imm32.c:5475: Test failed: unicode: got dwSize 40 imm32.c:5475: Test failed: unicode: got dwOffset[i] 32 imm32.c:5475: Test failed: unicode: got L"C" imm32.c:5475: Test failed: unicode: got dwOffset[i] 36 imm32.c:5475: Test failed: unicode: got L"C" imm32.c:5477: Test failed: unicode: ImmGetCandidateListA returned 96, error 0 imm32.c:5482: Test failed: unicode: ImmGetCandidateListA returned 96, error 0 imm32.c:5493: Test failed: unicode: got dwSize 96 imm32.c:5493: Test failed: unicode: got dwOffset[i] 36 imm32.c:5493: Test failed: unicode: got "C" imm32.c:5493: Test failed: unicode: got dwOffset[i] 64 imm32.c:5493: Test failed: unicode: got "C" imm32.c:5428: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5531: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5560: Test failed: unicode: ImmGetCandidateListCountW returned 172, error 0 imm32.c:5564: Test failed: unicode: ImmGetCandidateListCountA returned 144, error 0 imm32.c:5531: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5606: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5764: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5897: Test failed: unicode: 0: ImmGetCompositionStringW returned 2, error 0 imm32.c:5900: Test failed: unicode: 0: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5911: Test failed: unicode: 0: got buffer "R" imm32.c:5897: Test failed: unicode: 1: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 1: got buffer L"\cd00\cdcd\cdcd\cdcd" imm32.c:5897: Test failed: unicode: 3: ImmGetCompositionStringW returned 2, error 0 imm32.c:5901: Test failed: unicode: 3: got buffer L"C\cdcd\cdcd\cdcd" imm32.c:5912: Test failed: unicode: 3: got buffer "C" imm32.c:5897: Test failed: unicode: 4: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 4: got buffer L"\cd00\cdcd" imm32.c:5897: Test failed: unicode: 8: ImmGetCompositionStringW returned 2, error 0 imm32.c:5902: Test failed: unicode: 8: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5913: Test failed: unicode: 8: got buffer "R" imm32.c:5897: Test failed: unicode: 10: ImmGetCompositionStringW returned 2, error 0 imm32.c:5903: Test failed: unicode: 10: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5914: Test failed: unicode: 10: got buffer "R" imm32.c:5955: Test failed: unicode: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5764: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5955: Test failed: ansi: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 2: expected ImeSetCompositionString imm32.c:890: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:382: Test failed: unexpected call WM_IME_SETCONTEXT_ACTIVATE imm32.c:969: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:382: Test failed: unexpected call WM_IME_SETCONTEXT_ACTIVATE
=== w10pro64_zh_CN (64 bit report) ===
imm32: imm32.c:1250: Test failed: ImmGetCandidateWindow returned 0, error 0
On Tue Apr 11 07:19:26 2023 +0000, **** wrote:
Marvin replied on the mailing list:
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details: The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131738 Your paranoid android. === w1064v1809 (32 bit report) === imm32: imm32.c:5031: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:5031: Test failed: 1 (missing): hkl E020047F, himc 000200D5, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:4589: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_PROCESS_KEY vkey 0x41, key_data 0 imm32.c:5220: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5223: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5225: Test failed: 0 (missing): hkl E020047F, himc 00030072, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5232: Test failed: 4 (missing): hkl E020047F, himc 00090113, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5235: Test failed: 0 (missing): hkl E020047F, himc 00090113, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5764: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5897: Test failed: unicode: 0: ImmGetCompositionStringW returned 2, error 0 imm32.c:5900: Test failed: unicode: 0: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5911: Test failed: unicode: 0: got buffer "R" imm32.c:5897: Test failed: unicode: 1: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 1: got buffer L"\cd00\cdcd\cdcd\cdcd" imm32.c:5897: Test failed: unicode: 3: ImmGetCompositionStringW returned 2, error 0 imm32.c:5901: Test failed: unicode: 3: got buffer L"C\cdcd\cdcd\cdcd" imm32.c:5912: Test failed: unicode: 3: got buffer "C" imm32.c:5897: Test failed: unicode: 4: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 4: got buffer L"\cd00\cdcd" imm32.c:5897: Test failed: unicode: 8: ImmGetCompositionStringW returned 2, error 0 imm32.c:5902: Test failed: unicode: 8: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5913: Test failed: unicode: 8: got buffer "R" imm32.c:5897: Test failed: unicode: 10: ImmGetCompositionStringW returned 2, error 0 imm32.c:5903: Test failed: unicode: 10: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5914: Test failed: unicode: 10: got buffer "R" imm32.c:5955: Test failed: unicode: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5764: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5955: Test failed: ansi: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 2: expected ImeSetCompositionString === w11pro64 (32 bit report) === imm32: imm32.c:4986: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5031: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:5031: Test failed: 1 (missing): hkl E020047F, himc 00070143, IME_NOTIFY action 0x15, index 0x4, value 0 imm32.c:4578: Test failed: ImmLoadIME returned 0, error 126 imm32.c:4588: Test failed: got ret 0, error 0 imm32.c:4589: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_PROCESS_KEY vkey 0x41, key_data 0 imm32.c:5087: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5213: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5220: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5223: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5225: Test failed: 0 (missing): hkl E020047F, himc 000B0257, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5232: Test failed: 4 (missing): hkl E020047F, himc 000F02AF, IME_SET_ACTIVE_CONTEXT flag 0 imm32.c:5235: Test failed: 0 (missing): hkl E020047F, himc 000F02AF, IME_SET_ACTIVE_CONTEXT flag 1 imm32.c:5323: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5428: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5459: Test failed: unicode: ImmGetCandidateListW returned 40, error 0 imm32.c:5464: Test failed: unicode: ImmGetCandidateListW returned 40, error 0 imm32.c:5475: Test failed: unicode: got dwSize 40 imm32.c:5475: Test failed: unicode: got dwOffset[i] 32 imm32.c:5475: Test failed: unicode: got L"C" imm32.c:5475: Test failed: unicode: got dwOffset[i] 36 imm32.c:5475: Test failed: unicode: got L"C" imm32.c:5477: Test failed: unicode: ImmGetCandidateListA returned 96, error 0 imm32.c:5482: Test failed: unicode: ImmGetCandidateListA returned 96, error 0 imm32.c:5493: Test failed: unicode: got dwSize 96 imm32.c:5493: Test failed: unicode: got dwOffset[i] 36 imm32.c:5493: Test failed: unicode: got "C" imm32.c:5493: Test failed: unicode: got dwOffset[i] 64 imm32.c:5493: Test failed: unicode: got "C" imm32.c:5428: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5531: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5560: Test failed: unicode: ImmGetCandidateListCountW returned 172, error 0 imm32.c:5564: Test failed: unicode: ImmGetCandidateListCountA returned 144, error 0 imm32.c:5531: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5606: Test failed: ImmLoadIME returned 0, error 126 imm32.c:5764: Test failed: unicode: ImmLoadIME returned 0, error 126 imm32.c:5897: Test failed: unicode: 0: ImmGetCompositionStringW returned 2, error 0 imm32.c:5900: Test failed: unicode: 0: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5911: Test failed: unicode: 0: got buffer "R" imm32.c:5897: Test failed: unicode: 1: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 1: got buffer L"\cd00\cdcd\cdcd\cdcd" imm32.c:5897: Test failed: unicode: 3: ImmGetCompositionStringW returned 2, error 0 imm32.c:5901: Test failed: unicode: 3: got buffer L"C\cdcd\cdcd\cdcd" imm32.c:5912: Test failed: unicode: 3: got buffer "C" imm32.c:5897: Test failed: unicode: 4: ImmGetCompositionStringW returned 1, error 0 imm32.c:5904: Test failed: unicode: 4: got buffer L"\cd00\cdcd" imm32.c:5897: Test failed: unicode: 8: ImmGetCompositionStringW returned 2, error 0 imm32.c:5902: Test failed: unicode: 8: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5913: Test failed: unicode: 8: got buffer "R" imm32.c:5897: Test failed: unicode: 10: ImmGetCompositionStringW returned 2, error 0 imm32.c:5903: Test failed: unicode: 10: got buffer L"R\cdcd\cdcd\cdcd\cdcd\cdcd" imm32.c:5914: Test failed: unicode: 10: got buffer "R" imm32.c:5955: Test failed: unicode: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: unicode: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: unicode: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: unicode: 2: expected ImeSetCompositionString imm32.c:5764: Test failed: ansi: ImmLoadIME returned 0, error 126 imm32.c:5955: Test failed: ansi: 0: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 0: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 0: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 1: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 1: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 1: expected ImeSetCompositionString imm32.c:5955: Test failed: ansi: 2: ImmSetCompositionStringW returned 0, error 0 imm32.c:5956: Test failed: ansi: 2: expected ImeSetCompositionString imm32.c:5984: Test failed: ansi: 2: ImmSetCompositionStringA returned 0, error 0 imm32.c:5985: Test failed: ansi: 2: expected ImeSetCompositionString imm32.c:890: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:382: Test failed: unexpected call WM_IME_SETCONTEXT_ACTIVATE imm32.c:969: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:382: Test failed: unexpected call WM_IME_SETCONTEXT_ACTIVATE === w10pro64_zh_CN (64 bit report) === imm32: imm32.c:1250: Test failed: ImmGetCandidateWindow returned 0, error 0
`w10pro64_zh_CN` failure seems genuine, will have a look.