-- v2: imm32: Use INPUTCONTEXT directly in ImmSetConversionStatus. imm32: Use INPUTCONTEXT directly in ImmGetConversionStatus. imm32: Compare open status values in ImmSetOpenStatus. imm32: Cache INPUTCONTEXT values for every IME. imm32: Use INPUTCONTEXT directly in ImmSetOpenStatus. imm32: Use INPUTCONTEXT directly in ImmGetOpenStatus. imm32: Serialize ImeInquire / ImeDestroy calls. imm32/tests: Cleanup the cross thread IMC tests. imm32/tests: Reduce the number of IME installations.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 184 +++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 103 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 71d6b6ec64d..fa39541c7f3 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2582,7 +2582,7 @@ static IMEINFO ime_info; static UINT ime_count; static WCHAR ime_path[MAX_PATH]; static HIMC default_himc; -static HKL default_hkl; +static HKL default_hkl, wineime_hkl; static HKL expect_ime = (HKL)(int)0xe020047f;
enum ime_function @@ -3429,12 +3429,8 @@ static void test_ImmInstallIME(void) ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %#x\n", ret );
- ime_cleanup( hkl, FALSE ); - ime_info.fdwProperty = 0;
- if (!(hkl = ime_install())) goto cleanup; - SET_EXPECT( IME_DLL_PROCESS_ATTACH ); SET_EXPECT( ImeInquire ); ret = ImmLoadIME( hkl ); @@ -3481,7 +3477,7 @@ static void test_ImmIsIME(void) /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ ime_info.fdwProperty = IME_PROP_END_UNLOAD;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
todo_ImeInquire = TRUE; todo_ImeDestroy = TRUE; @@ -3493,8 +3489,6 @@ static void test_ImmIsIME(void) todo_ImeInquire = FALSE; todo_ImeDestroy = FALSE;
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); SET_ENABLE( ImeInquire, FALSE ); @@ -3566,7 +3560,7 @@ static void test_ImmGetProperty(void) /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ ime_info.fdwProperty = IME_PROP_END_UNLOAD;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
SET_EXPECT( ImeInquire ); SET_EXPECT( ImeDestroy ); @@ -3589,8 +3583,6 @@ static void test_ImmGetProperty(void) todo_ImeDestroy = FALSE; called_ImeDestroy = FALSE;
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeInquire, FALSE ); SET_ENABLE( ImeDestroy, FALSE ); @@ -3624,7 +3616,7 @@ static void test_ImmGetDescription(void) ret = GetLastError(); ok( ret == 0xdeadbeef, "got error %lu\n", ret );
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetDescriptionW( hkl, bufferW, 2 ); @@ -3662,8 +3654,6 @@ static void test_ImmGetDescription(void) ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) );
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); SET_ENABLE( ImeInquire, FALSE ); @@ -3699,7 +3689,7 @@ static void test_ImmGetIMEFileName(void) ret = GetLastError(); ok( ret == 0xdeadbeef, "got error %lu\n", ret );
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 2 ); @@ -3741,8 +3731,6 @@ static void test_ImmGetIMEFileName(void) ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) );
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); SET_ENABLE( ImeInquire, FALSE ); @@ -3778,7 +3766,7 @@ static void test_ImmEscape( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
for (i = 0; i < ARRAY_SIZE(codes); ++i) { @@ -3849,8 +3837,6 @@ static void test_ImmEscape( BOOL unicode ) winetest_pop_context(); }
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeEscape, FALSE );
@@ -3899,7 +3885,7 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
SET_EXPECT( ImeEnumRegisterWord ); ok_ret( 0, ImmEnumRegisterWordW( hkl, enum_register_wordW, NULL, 0, NULL, NULL ) ); @@ -3917,8 +3903,6 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl, enum_register_wordA, "Reading", 0xdeadbeef, "String", NULL ) ); CHECK_CALLED( ImeEnumRegisterWord );
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeEnumRegisterWord, FALSE );
@@ -3945,7 +3929,7 @@ static void test_ImmRegisterWord( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
SET_EXPECT( ImeRegisterWord ); ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, NULL ) ); @@ -3979,8 +3963,6 @@ static void test_ImmRegisterWord( BOOL unicode ) ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeRegisterWord );
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeRegisterWord, FALSE );
@@ -4009,7 +3991,7 @@ static void test_ImmGetRegisterWordStyle( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
if (!strcmp( winetest_platform, "wine" )) goto skip_null;
@@ -4056,8 +4038,6 @@ skip_null: } CHECK_CALLED( ImeGetRegisterWordStyle );
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeGetRegisterWordStyle, FALSE );
@@ -4084,7 +4064,7 @@ static void test_ImmUnregisterWord( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
SET_EXPECT( ImeUnregisterWord ); ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, NULL ) ); @@ -4118,8 +4098,6 @@ static void test_ImmUnregisterWord( BOOL unicode ) ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeUnregisterWord );
- ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeUnregisterWord, FALSE );
@@ -4194,7 +4172,7 @@ static void test_ImmSetConversionStatus(void) {0}, }; DWORD old_conversion, old_sentence, conversion, sentence; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; INPUTCONTEXT *ctx;
ok_ret( 0, ImmGetConversionStatus( 0, &old_conversion, &old_sentence ) ); @@ -4225,7 +4203,7 @@ static void test_ImmSetConversionStatus(void)
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4290,17 +4268,17 @@ static void test_ImmSetConversionStatus(void) ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" );
/* status is cached and some bits are kept from the previous active IME */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); 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_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" );
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) );
cleanup: /* sanitize conversion status to some sane default */ @@ -4365,7 +4343,7 @@ static void test_ImmSetOpenStatus(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; DWORD old_status, status; INPUTCONTEXT *ctx;
@@ -4392,7 +4370,7 @@ static void test_ImmSetOpenStatus(void)
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4447,7 +4425,7 @@ static void test_ImmSetOpenStatus(void)
/* status is cached between IME activations */
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); status = ImmGetOpenStatus( default_himc ); todo_wine ok_eq( old_status, status, UINT, "%#x" ); todo_wine ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); @@ -4456,12 +4434,12 @@ static void test_ImmSetOpenStatus(void) todo_wine ok_eq( 1, status, UINT, "%#x" ); todo_wine ok_eq( 1, ctx->fOpen, UINT, "%#x" ); ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); status = ImmGetOpenStatus( default_himc ); ok_eq( old_status, status, UINT, "%#x" ); ok_eq( old_status, ctx->fOpen, UINT, "%#x" );
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) );
cleanup: /* sanitize open status to some sane default */ @@ -4488,7 +4466,7 @@ static void test_ImmProcessKey(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; UINT_PTR ret;
hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, @@ -4496,12 +4474,12 @@ static void test_ImmProcessKey(void) ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); process_messages();
- ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); ok_seq( empty_sequence );
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4518,13 +4496,13 @@ static void test_ImmProcessKey(void) ok_seq( process_key_seq );
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); ok_seq( empty_sequence ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) );
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); process_messages(); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -4658,7 +4636,7 @@ static void test_ImmActivateLayout(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; struct ime_windows ime_windows = {0}; HIMC himc; UINT ret; @@ -4666,20 +4644,20 @@ static void test_ImmActivateLayout(void) SET_ENABLE( ImeInquire, TRUE ); SET_ENABLE( ImeDestroy, TRUE );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) );
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
/* ActivateKeyboardLayout doesn't call ImeInquire / ImeDestroy */
ok_seq( empty_sequence ); - ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); ok_seq( empty_sequence ); - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
/* ImmActivateLayout changes active HKL */ @@ -4696,14 +4674,11 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence );
todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_seq( deactivate_seq ); todo_ImeDestroy = FALSE;
- ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - - ime_cleanup( hkl, FALSE ); - ok_seq( empty_sequence ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
/* ImmActivateLayout leaks the IME, we need to free it manually */ @@ -4717,8 +4692,6 @@ static void test_ImmActivateLayout(void)
/* when there's a window, ActivateKeyboardLayout calls ImeInquire */
- if (!(hkl = ime_install())) goto cleanup; - hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); @@ -4730,7 +4703,7 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence );
SET_EXPECT( ImeInquire ); - ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); CHECK_CALLED( ImeInquire ); activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); @@ -4746,20 +4719,20 @@ static void test_ImmActivateLayout(void) ime_call_count = 0;
todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ - ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, ActivateKeyboardLayout( default_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 );
- ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
ok_ret( 1, ImmDestroyContext( himc ) ); ok_seq( empty_sequence );
todo_ImeInquire = TRUE; - ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -4769,13 +4742,14 @@ static void test_ImmActivateLayout(void) 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" ); + ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); todo_ImeDestroy = FALSE; - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + process_messages();
SET_EXPECT( ImeDestroy ); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); CHECK_CALLED( ImeDestroy );
ok_ret( 1, DestroyWindow( hwnd ) ); @@ -4883,7 +4857,7 @@ static void test_ImmCreateInputContext(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; INPUTCONTEXT *ctx; HIMC himc[2]; HWND hwnd; @@ -4920,7 +4894,7 @@ static void test_ImmCreateInputContext(void) ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; ime_info.dwPrivateDataSize = 123;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
ok_ret( 1, ImmLoadIME( hkl ) );
@@ -4964,14 +4938,14 @@ static void test_ImmCreateInputContext(void)
/* Deactivating the layout calls ImeSelect 0 on existing HIMC */
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); deactivate_seq[1].himc = himc[0]; deactivate_seq[5].himc = himc[0]; ok_seq( deactivate_seq );
- ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); ok_seq( empty_sequence );
cleanup: @@ -5011,12 +4985,12 @@ static void test_DefWindowProc(void) {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY}}, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; UINT_PTR ret;
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return;
hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5059,11 +5033,11 @@ static void test_DefWindowProc(void) ok_ret( 0, ret ); ok_seq( empty_sequence );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5137,12 +5111,12 @@ static void test_ImmSetActiveContext(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; HIMC himc;
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return;
hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5174,11 +5148,11 @@ static void test_ImmSetActiveContext(void) ok_seq( activate_1_seq ); ok_ret( 1, ImmDestroyContext( himc ) );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5241,7 +5215,7 @@ static void test_ImmRequestMessage(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; COMPOSITIONFORM comp_form = {0}; IMECHARPOSITION char_pos = {0}; RECONVERTSTRING reconv = {0}; @@ -5250,7 +5224,7 @@ static void test_ImmRequestMessage(void) INPUTCONTEXT *ctx; HIMC himc;
- if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return;
hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5309,11 +5283,11 @@ static void test_ImmRequestMessage(void) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5322,7 +5296,7 @@ static void test_ImmGetCandidateList( BOOL unicode ) { char buffer[512], expect_bufW[512] = {0}, expect_bufA[512] = {0}; CANDIDATELIST *cand_list = (CANDIDATELIST *)buffer, *expect_listW, *expect_listA; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; CANDIDATEINFO *cand_info; INPUTCONTEXT *ctx; HIMC himc; @@ -5357,7 +5331,7 @@ static void test_ImmGetCandidateList( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5434,11 +5408,11 @@ static void test_ImmGetCandidateList( BOOL unicode ) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
@@ -5448,7 +5422,7 @@ cleanup:
static void test_ImmGetCandidateListCount( BOOL unicode ) { - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; CANDIDATEINFO *cand_info; INPUTCONTEXT *ctx; DWORD count; @@ -5460,7 +5434,7 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5507,11 +5481,11 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
@@ -5521,7 +5495,7 @@ cleanup:
static void test_ImmGetCandidateWindow(void) { - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; const CANDIDATEFORM expect_form = { .dwIndex = 0xdeadbeef, @@ -5535,7 +5509,7 @@ static void test_ImmGetCandidateWindow(void)
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
- if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return;
hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5584,11 +5558,11 @@ static void test_ImmGetCandidateWindow(void) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5675,7 +5649,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) }; static const UINT expect_retW[ARRAY_SIZE(gcs_indexes)] = {16, 8, 8, 8, 4, 8, 3, 1, 20, 8, 12, 8}; static const UINT expect_retA[ARRAY_SIZE(gcs_indexes)] = {8, 8, 8, 4, 4, 8, 3, 1, 10, 8, 6, 8}; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; COMPOSITIONSTRING *string; char buffer[1024]; INPUTCONTEXT *old_ctx, *ctx; @@ -5693,7 +5667,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
- if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup;
hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5938,7 +5912,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) ok_ret( 1, ImmUnlockIMC( himc ) );
/* composition strings are kept between IME selections */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ctx = ImmLockIMC( himc ); ok_eq( old_ctx, ctx, INPUTCONTEXT *, "%p" ); ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); @@ -5949,18 +5923,18 @@ static void test_ImmGetCompositionString( BOOL unicode ) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); check_composition_string( string, &expect_string_empty ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); check_composition_string( string, &expect_string_empty );
ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) );
- ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
- ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
@@ -5987,6 +5961,8 @@ START_TEST(imm32) test_ImmEnumInputContext();
test_ImmInstallIME(); + wineime_hkl = ime_install(); + test_ImmGetDescription(); test_ImmGetIMEFileName(); test_ImmIsIME(); @@ -6024,6 +6000,8 @@ START_TEST(imm32) test_ImmGetCompositionString( TRUE ); test_ImmGetCompositionString( FALSE );
+ if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); + if (init()) { test_ImmNotifyIME();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 543 ++++++++++++++++++++++----------------- 1 file changed, 311 insertions(+), 232 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index fa39541c7f3..827a1326e3e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -986,256 +986,335 @@ 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; + CANDIDATEFORM candidate = {.dwIndex = 1, .dwStyle = CFS_CANDIDATEPOS}; + struct test_cross_thread_himc_params *params = arg; + COMPOSITIONFORM composition = {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; + UINT ret;
- 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);
- 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"); + 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" ); + ret = ImmGetIMCLockCount( params.himc[0] ); + ok( ret >= 2, "got ret %u\n", ret ); + + 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" ); + ret = ImmGetIMCLockCount( params.himc[1] ); + ok( ret >= 2, "got ret %u\n", ret ); + 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 ) ); + + /* 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( 1, ImmGetCandidateWindow( params.himc[0], 1, &candidate ) ); + ok_ret( 1, ImmGetCandidateWindow( params.himc[1], 1, &candidate ) ); + ok_ret( 0, ImmSetCandidateWindow( params.himc[0], &candidate ) ); + ok_ret( 0, ImmSetCandidateWindow( params.himc[1], &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) @@ -6009,7 +6088,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 827a1326e3e..88b167c701d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4351,8 +4351,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( default_hkl ) ); todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); @@ -4506,8 +4506,8 @@ static void test_ImmSetOpenStatus(void)
ok_ret( 1, ImmActivateLayout( default_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" ); @@ -4752,10 +4752,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( default_hkl ) ); ok_seq( deactivate_seq ); - todo_ImeDestroy = FALSE;
ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -4786,9 +4784,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" );
@@ -4797,9 +4793,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( default_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 ); @@ -4810,9 +4804,7 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence );
- todo_ImeInquire = TRUE; ok_eq( default_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 ) ); @@ -4820,9 +4812,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( default_hkl, 0 ), HKL, "%p" ); - todo_ImeDestroy = FALSE; ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); process_messages();
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 88b167c701d..8c6d441181b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4399,7 +4399,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}, }; @@ -4408,17 +4407,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}, }; @@ -4483,8 +4479,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 ); @@ -4492,15 +4488,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 8c6d441181b..bbfae7e65d1 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4219,7 +4219,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=131764
Your paranoid android.
=== w10pro64_ja (64 bit report) ===
Report validation errors: imm32:imm32 has no test summary line (early exit of the main process?) imm32:imm32 returned a non-zero exit code despite reporting no failures
v2: Fix `ImmGetCandidateWindow` failures on zh_CN locale. Add a change to reduce the number of IME installations and the related spurious failures.