1 /* 2 * Unit tests for imm32 3 * 4 * Copyright (c) 2008 Michael Jung 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdio.h> 22 23 #include "wine/test.h" 24 #include "winuser.h" 25 #include "wingdi.h" 26 #include "imm.h" 27 #include "ddk/imm.h" 28 29 static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD); 30 static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM); 31 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); 32 33 /* 34 * msgspy - record and analyse message traces sent to a certain window 35 */ 36 typedef struct _msgs { 37 CWPSTRUCT msg; 38 BOOL post; 39 } imm_msgs; 40 41 static struct _msg_spy { 42 HWND hwnd; 43 HHOOK get_msg_hook; 44 HHOOK call_wnd_proc_hook; 45 imm_msgs msgs[64]; 46 unsigned int i_msg; 47 } msg_spy; 48 49 typedef struct 50 { 51 DWORD type; 52 union 53 { 54 MOUSEINPUT mi; 55 KEYBDINPUT ki; 56 HARDWAREINPUT hi; 57 } u; 58 } TEST_INPUT; 59 60 typedef struct _tagTRANSMSG { 61 UINT message; 62 WPARAM wParam; 63 LPARAM lParam; 64 } TRANSMSG, *LPTRANSMSG; 65 66 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); 67 68 static LRESULT CALLBACK get_msg_filter(int nCode, WPARAM wParam, LPARAM lParam) 69 { 70 if (HC_ACTION == nCode) { 71 MSG *msg = (MSG*)lParam; 72 73 if ((msg->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL) && 74 (msg_spy.i_msg < ARRAY_SIZE(msg_spy.msgs))) 75 { 76 msg_spy.msgs[msg_spy.i_msg].msg.hwnd = msg->hwnd; 77 msg_spy.msgs[msg_spy.i_msg].msg.message = msg->message; 78 msg_spy.msgs[msg_spy.i_msg].msg.wParam = msg->wParam; 79 msg_spy.msgs[msg_spy.i_msg].msg.lParam = msg->lParam; 80 msg_spy.msgs[msg_spy.i_msg].post = TRUE; 81 msg_spy.i_msg++; 82 } 83 } 84 85 return CallNextHookEx(msg_spy.get_msg_hook, nCode, wParam, lParam); 86 } 87 88 static LRESULT CALLBACK call_wnd_proc_filter(int nCode, WPARAM wParam, 89 LPARAM lParam) 90 { 91 if (HC_ACTION == nCode) { 92 CWPSTRUCT *cwp = (CWPSTRUCT*)lParam; 93 94 if (((cwp->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL)) && 95 (msg_spy.i_msg < ARRAY_SIZE(msg_spy.msgs))) 96 { 97 memcpy(&msg_spy.msgs[msg_spy.i_msg].msg, cwp, sizeof(msg_spy.msgs[0].msg)); 98 msg_spy.msgs[msg_spy.i_msg].post = FALSE; 99 msg_spy.i_msg++; 100 } 101 } 102 103 return CallNextHookEx(msg_spy.call_wnd_proc_hook, nCode, wParam, lParam); 104 } 105 106 static void msg_spy_pump_msg_queue(void) { 107 MSG msg; 108 109 while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { 110 TranslateMessage(&msg); 111 DispatchMessageW(&msg); 112 } 113 114 return; 115 } 116 117 static void msg_spy_flush_msgs(void) { 118 msg_spy_pump_msg_queue(); 119 msg_spy.i_msg = 0; 120 } 121 122 static imm_msgs* msg_spy_find_next_msg(UINT message, UINT *start) { 123 UINT i; 124 125 msg_spy_pump_msg_queue(); 126 127 if (msg_spy.i_msg >= ARRAY_SIZE(msg_spy.msgs)) 128 fprintf(stdout, "%s:%d: msg_spy: message buffer overflow!\n", 129 __FILE__, __LINE__); 130 131 for (i = *start; i < msg_spy.i_msg; i++) 132 if (msg_spy.msgs[i].msg.message == message) 133 { 134 *start = i+1; 135 return &msg_spy.msgs[i]; 136 } 137 138 return NULL; 139 } 140 141 static imm_msgs* msg_spy_find_msg(UINT message) { 142 UINT i = 0; 143 144 return msg_spy_find_next_msg(message, &i); 145 } 146 147 static void msg_spy_init(HWND hwnd) { 148 msg_spy.hwnd = hwnd; 149 msg_spy.get_msg_hook = 150 SetWindowsHookExW(WH_GETMESSAGE, get_msg_filter, GetModuleHandleW(NULL), 151 GetCurrentThreadId()); 152 msg_spy.call_wnd_proc_hook = 153 SetWindowsHookExW(WH_CALLWNDPROC, call_wnd_proc_filter, 154 GetModuleHandleW(NULL), GetCurrentThreadId()); 155 msg_spy.i_msg = 0; 156 157 msg_spy_flush_msgs(); 158 } 159 160 static void msg_spy_cleanup(void) { 161 if (msg_spy.get_msg_hook) 162 UnhookWindowsHookEx(msg_spy.get_msg_hook); 163 if (msg_spy.call_wnd_proc_hook) 164 UnhookWindowsHookEx(msg_spy.call_wnd_proc_hook); 165 memset(&msg_spy, 0, sizeof(msg_spy)); 166 } 167 168 /* 169 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the 170 * messages being sent to this window in response. 171 */ 172 static const char wndcls[] = "winetest_imm32_wndcls"; 173 static enum { PHASE_UNKNOWN, FIRST_WINDOW, SECOND_WINDOW, 174 CREATE_CANCEL, NCCREATE_CANCEL, IME_DISABLED } test_phase; 175 static HWND hwnd; 176 177 static HWND get_ime_window(void); 178 179 static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 180 { 181 HWND default_ime_wnd; 182 switch (msg) 183 { 184 case WM_IME_SETCONTEXT: 185 return TRUE; 186 case WM_NCCREATE: 187 default_ime_wnd = get_ime_window(); 188 switch(test_phase) { 189 case FIRST_WINDOW: 190 case IME_DISABLED: 191 ok(!default_ime_wnd, "expected no IME windows\n"); 192 break; 193 case SECOND_WINDOW: 194 ok(default_ime_wnd != NULL, "expected IME window existence\n"); 195 break; 196 default: 197 break; /* do nothing */ 198 } 199 if (test_phase == NCCREATE_CANCEL) 200 return FALSE; 201 return TRUE; 202 case WM_NCCALCSIZE: 203 default_ime_wnd = get_ime_window(); 204 switch(test_phase) { 205 case FIRST_WINDOW: 206 case SECOND_WINDOW: 207 case CREATE_CANCEL: 208 ok(default_ime_wnd != NULL, "expected IME window existence\n"); 209 break; 210 case IME_DISABLED: 211 ok(!default_ime_wnd, "expected no IME windows\n"); 212 break; 213 default: 214 break; /* do nothing */ 215 } 216 break; 217 case WM_CREATE: 218 default_ime_wnd = get_ime_window(); 219 switch(test_phase) { 220 case FIRST_WINDOW: 221 case SECOND_WINDOW: 222 case CREATE_CANCEL: 223 ok(default_ime_wnd != NULL, "expected IME window existence\n"); 224 break; 225 case IME_DISABLED: 226 ok(!default_ime_wnd, "expected no IME windows\n"); 227 break; 228 default: 229 break; /* do nothing */ 230 } 231 if (test_phase == CREATE_CANCEL) 232 return -1; 233 return TRUE; 234 } 235 236 return DefWindowProcA(hWnd,msg,wParam,lParam); 237 } 238 239 static BOOL init(void) { 240 WNDCLASSEXA wc; 241 HIMC imc; 242 HMODULE hmod,huser; 243 244 hmod = GetModuleHandleA("imm32.dll"); 245 huser = GetModuleHandleA("user32"); 246 pImmAssociateContextEx = (void*)GetProcAddress(hmod, "ImmAssociateContextEx"); 247 pImmIsUIMessageA = (void*)GetProcAddress(hmod, "ImmIsUIMessageA"); 248 pSendInput = (void*)GetProcAddress(huser, "SendInput"); 249 250 wc.cbSize = sizeof(WNDCLASSEXA); 251 wc.style = 0; 252 wc.lpfnWndProc = wndProc; 253 wc.cbClsExtra = 0; 254 wc.cbWndExtra = 0; 255 wc.hInstance = GetModuleHandleA(NULL); 256 wc.hIcon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); 257 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); 258 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 259 wc.lpszMenuName = NULL; 260 wc.lpszClassName = wndcls; 261 wc.hIconSm = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); 262 263 if (!RegisterClassExA(&wc)) 264 return FALSE; 265 266 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 267 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 268 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 269 if (!hwnd) 270 return FALSE; 271 272 imc = ImmGetContext(hwnd); 273 if (!imc) 274 { 275 win_skip("IME support not implemented\n"); 276 return FALSE; 277 } 278 ImmReleaseContext(hwnd, imc); 279 280 ShowWindow(hwnd, SW_SHOWNORMAL); 281 UpdateWindow(hwnd); 282 283 msg_spy_init(hwnd); 284 285 return TRUE; 286 } 287 288 static void cleanup(void) { 289 msg_spy_cleanup(); 290 if (hwnd) 291 DestroyWindow(hwnd); 292 UnregisterClassA(wndcls, GetModuleHandleW(NULL)); 293 } 294 295 static void test_ImmNotifyIME(void) { 296 static const char string[] = "wine"; 297 char resstr[16] = ""; 298 HIMC imc; 299 BOOL ret; 300 301 imc = ImmGetContext(hwnd); 302 msg_spy_flush_msgs(); 303 304 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 305 ok(broken(!ret) || 306 ret, /* Vista+ */ 307 "Canceling an empty composition string should succeed.\n"); 308 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post " 309 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if " 310 "the composition string being canceled is empty.\n"); 311 312 ImmSetCompositionStringA(imc, SCS_SETSTR, string, sizeof(string), NULL, 0); 313 msg_spy_flush_msgs(); 314 315 ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 316 msg_spy_flush_msgs(); 317 318 /* behavior differs between win9x and NT */ 319 ret = ImmGetCompositionStringA(imc, GCS_COMPSTR, resstr, sizeof(resstr)); 320 ok(!ret, "After being cancelled the composition string is empty.\n"); 321 322 msg_spy_flush_msgs(); 323 324 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 325 ok(broken(!ret) || 326 ret, /* Vista+ */ 327 "Canceling an empty composition string should succeed.\n"); 328 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post " 329 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if " 330 "the composition string being canceled is empty.\n"); 331 332 msg_spy_flush_msgs(); 333 ImmReleaseContext(hwnd, imc); 334 335 imc = ImmCreateContext(); 336 ImmDestroyContext(imc); 337 338 SetLastError(0xdeadbeef); 339 ret = ImmNotifyIME((HIMC)0xdeadcafe, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 340 ok (ret == 0, "Bad IME should return 0\n"); 341 ret = GetLastError(); 342 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 343 SetLastError(0xdeadbeef); 344 ret = ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 345 ok (ret == 0, "NULL IME should return 0\n"); 346 ret = GetLastError(); 347 ok(ret == ERROR_SUCCESS, "wrong last error %08x!\n", ret); 348 SetLastError(0xdeadbeef); 349 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 350 ok (ret == 0, "Destroyed IME should return 0\n"); 351 ret = GetLastError(); 352 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 353 354 } 355 356 static struct { 357 WNDPROC old_wnd_proc; 358 BOOL catch_result_str; 359 BOOL catch_ime_char; 360 DWORD start; 361 DWORD timer_id; 362 } ime_composition_test; 363 364 static LRESULT WINAPI test_ime_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 365 { 366 switch (msg) 367 { 368 case WM_IME_COMPOSITION: 369 if ((lParam & GCS_RESULTSTR) && !ime_composition_test.catch_result_str) { 370 HWND hwndIme; 371 WCHAR wstring[20]; 372 HIMC imc; 373 LONG size; 374 LRESULT ret; 375 376 hwndIme = ImmGetDefaultIMEWnd(hWnd); 377 ok(hwndIme != NULL, "expected IME window existence\n"); 378 379 ok(!ime_composition_test.catch_ime_char, "WM_IME_CHAR is sent\n"); 380 ret = CallWindowProcA(ime_composition_test.old_wnd_proc, 381 hWnd, msg, wParam, lParam); 382 ok(ime_composition_test.catch_ime_char, "WM_IME_CHAR isn't sent\n"); 383 384 ime_composition_test.catch_ime_char = FALSE; 385 SendMessageA(hwndIme, msg, wParam, lParam); 386 ok(!ime_composition_test.catch_ime_char, "WM_IME_CHAR is sent\n"); 387 388 imc = ImmGetContext(hWnd); 389 size = ImmGetCompositionStringW(imc, GCS_RESULTSTR, 390 wstring, sizeof(wstring)); 391 ok(size > 0, "ImmGetCompositionString(GCS_RESULTSTR) is %d\n", size); 392 ImmReleaseContext(hwnd, imc); 393 394 ime_composition_test.catch_result_str = TRUE; 395 return ret; 396 } 397 break; 398 case WM_IME_CHAR: 399 if (!ime_composition_test.catch_result_str) 400 ime_composition_test.catch_ime_char = TRUE; 401 break; 402 case WM_TIMER: 403 if (wParam == ime_composition_test.timer_id) { 404 HWND parent = GetParent(hWnd); 405 char title[64]; 406 int left = 20 - (GetTickCount() - ime_composition_test.start) / 1000; 407 wsprintfA(title, "%sLeft %d sec. - IME composition test", 408 ime_composition_test.catch_result_str ? "[*] " : "", left); 409 SetWindowTextA(parent, title); 410 if (left <= 0) 411 DestroyWindow(parent); 412 else 413 SetTimer(hWnd, wParam, 100, NULL); 414 return TRUE; 415 } 416 break; 417 } 418 return CallWindowProcA(ime_composition_test.old_wnd_proc, 419 hWnd, msg, wParam, lParam); 420 } 421 422 static void test_ImmGetCompositionString(void) 423 { 424 HIMC imc; 425 static const WCHAR string[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e}; 426 char cstring[20]; 427 WCHAR wstring[20]; 428 LONG len; 429 LONG alen,wlen; 430 BOOL ret; 431 DWORD prop; 432 433 imc = ImmGetContext(hwnd); 434 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL,0); 435 if (!ret) { 436 win_skip("Composition isn't supported\n"); 437 ImmReleaseContext(hwnd, imc); 438 return; 439 } 440 msg_spy_flush_msgs(); 441 442 alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20); 443 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20); 444 /* windows machines without any IME installed just return 0 above */ 445 if( alen && wlen) 446 { 447 len = ImmGetCompositionStringW(imc, GCS_COMPATTR, NULL, 0); 448 ok(len*sizeof(WCHAR)==wlen,"GCS_COMPATTR(W) not returning correct count\n"); 449 len = ImmGetCompositionStringA(imc, GCS_COMPATTR, NULL, 0); 450 ok(len==alen,"GCS_COMPATTR(A) not returning correct count\n"); 451 452 /* Get strings with exactly matching buffer sizes. */ 453 memset(wstring, 0x1a, sizeof(wstring)); 454 memset(cstring, 0x1a, sizeof(cstring)); 455 456 len = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, alen); 457 ok(len == alen, "Unexpected length %d.\n", len); 458 ok(cstring[alen] == 0x1a, "Unexpected buffer contents.\n"); 459 460 len = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, wlen); 461 ok(len == wlen, "Unexpected length %d.\n", len); 462 ok(wstring[wlen/sizeof(WCHAR)] == 0x1a1a, "Unexpected buffer contents.\n"); 463 464 /* Get strings with exactly smaller buffer sizes. */ 465 memset(wstring, 0x1a, sizeof(wstring)); 466 memset(cstring, 0x1a, sizeof(cstring)); 467 468 /* Returns 0 but still fills buffer. */ 469 len = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, alen - 1); 470 ok(!len, "Unexpected length %d.\n", len); 471 ok(cstring[0] == 'w', "Unexpected buffer contents %s.\n", cstring); 472 473 len = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, wlen - 1); 474 ok(len == wlen - 1, "Unexpected length %d.\n", len); 475 ok(!memcmp(wstring, string, wlen - 1), "Unexpected buffer contents.\n"); 476 477 /* Get the size of the required output buffer. */ 478 memset(wstring, 0x1a, sizeof(wstring)); 479 memset(cstring, 0x1a, sizeof(cstring)); 480 481 len = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 0); 482 ok(len == alen, "Unexpected length %d.\n", len); 483 ok(cstring[0] == 0x1a, "Unexpected buffer contents %s.\n", cstring); 484 485 len = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 0); 486 ok(len == wlen, "Unexpected length %d.\n", len); 487 ok(wstring[0] == 0x1a1a, "Unexpected buffer contents.\n"); 488 } 489 else 490 win_skip("Composition string isn't available\n"); 491 492 ImmReleaseContext(hwnd, imc); 493 494 /* Test composition results input by IMM API */ 495 prop = ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR); 496 if (!(prop & SCS_CAP_COMPSTR)) { 497 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */ 498 skip("This IME doesn't support SCS_SETSTR\n"); 499 } 500 else { 501 ime_composition_test.old_wnd_proc = 502 (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, 503 (LONG_PTR)test_ime_wnd_proc); 504 imc = ImmGetContext(hwnd); 505 msg_spy_flush_msgs(); 506 507 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, 508 string, sizeof(string), NULL,0); 509 ok(ret, "ImmSetCompositionStringW failed\n"); 510 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, 511 wstring, sizeof(wstring)); 512 if (wlen > 0) { 513 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 514 ok(ret, "ImmNotifyIME(CPS_COMPLETE) failed\n"); 515 msg_spy_flush_msgs(); 516 ok(ime_composition_test.catch_result_str, 517 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n"); 518 } 519 else 520 win_skip("Composition string isn't available\n"); 521 ImmReleaseContext(hwnd, imc); 522 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, 523 (LONG_PTR)ime_composition_test.old_wnd_proc); 524 msg_spy_flush_msgs(); 525 } 526 527 /* Test composition results input by hand */ 528 memset(&ime_composition_test, 0, sizeof(ime_composition_test)); 529 if (winetest_interactive) { 530 HWND hwndMain, hwndChild; 531 MSG msg; 532 const DWORD MY_TIMER = 0xcaffe; 533 534 hwndMain = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, 535 "IME composition test", 536 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 537 CW_USEDEFAULT, CW_USEDEFAULT, 320, 160, 538 NULL, NULL, GetModuleHandleA(NULL), NULL); 539 hwndChild = CreateWindowExA(0, "static", 540 "Input a DBCS character here using IME.", 541 WS_CHILD | WS_VISIBLE, 542 0, 0, 320, 100, hwndMain, NULL, 543 GetModuleHandleA(NULL), NULL); 544 545 ime_composition_test.old_wnd_proc = 546 (WNDPROC)SetWindowLongPtrA(hwndChild, GWLP_WNDPROC, 547 (LONG_PTR)test_ime_wnd_proc); 548 549 SetFocus(hwndChild); 550 551 ime_composition_test.timer_id = MY_TIMER; 552 ime_composition_test.start = GetTickCount(); 553 SetTimer(hwndChild, ime_composition_test.timer_id, 100, NULL); 554 while (GetMessageA(&msg, NULL, 0, 0)) { 555 TranslateMessage(&msg); 556 DispatchMessageA(&msg); 557 if (!IsWindow(hwndMain)) 558 break; 559 } 560 if (!ime_composition_test.catch_result_str) 561 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n"); 562 msg_spy_flush_msgs(); 563 } 564 } 565 566 static void test_ImmSetCompositionString(void) 567 { 568 HIMC imc; 569 BOOL ret; 570 571 SetLastError(0xdeadbeef); 572 imc = ImmGetContext(hwnd); 573 ok(imc != 0, "ImmGetContext() failed. Last error: %u\n", GetLastError()); 574 if (!imc) 575 return; 576 577 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 0, NULL, 0); 578 ok(broken(!ret) || 579 ret, /* Vista+ */ 580 "ImmSetCompositionStringW() failed.\n"); 581 582 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR, 583 NULL, 0, NULL, 0); 584 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 585 586 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGECLAUSE, 587 NULL, 0, NULL, 0); 588 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 589 590 ret = ImmSetCompositionStringW(imc, SCS_CHANGEATTR | SCS_CHANGECLAUSE, 591 NULL, 0, NULL, 0); 592 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 593 594 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR | SCS_CHANGECLAUSE, 595 NULL, 0, NULL, 0); 596 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 597 598 ImmReleaseContext(hwnd, imc); 599 } 600 601 static void test_ImmIME(void) 602 { 603 HIMC imc; 604 605 imc = ImmGetContext(hwnd); 606 if (imc) 607 { 608 BOOL rc; 609 rc = ImmConfigureIMEA(imc, NULL, IME_CONFIG_REGISTERWORD, NULL); 610 ok (rc == 0, "ImmConfigureIMEA did not fail\n"); 611 rc = ImmConfigureIMEW(imc, NULL, IME_CONFIG_REGISTERWORD, NULL); 612 ok (rc == 0, "ImmConfigureIMEW did not fail\n"); 613 } 614 ImmReleaseContext(hwnd,imc); 615 } 616 617 static void test_ImmAssociateContextEx(void) 618 { 619 HIMC imc; 620 BOOL rc; 621 622 if (!pImmAssociateContextEx) return; 623 624 imc = ImmGetContext(hwnd); 625 if (imc) 626 { 627 HIMC retimc, newimc; 628 629 newimc = ImmCreateContext(); 630 ok(newimc != imc, "handles should not be the same\n"); 631 rc = pImmAssociateContextEx(NULL, NULL, 0); 632 ok(!rc, "ImmAssociateContextEx succeeded\n"); 633 rc = pImmAssociateContextEx(hwnd, NULL, 0); 634 ok(rc, "ImmAssociateContextEx failed\n"); 635 rc = pImmAssociateContextEx(NULL, imc, 0); 636 ok(!rc, "ImmAssociateContextEx succeeded\n"); 637 638 rc = pImmAssociateContextEx(hwnd, imc, 0); 639 ok(rc, "ImmAssociateContextEx failed\n"); 640 retimc = ImmGetContext(hwnd); 641 ok(retimc == imc, "handles should be the same\n"); 642 ImmReleaseContext(hwnd,retimc); 643 644 rc = pImmAssociateContextEx(hwnd, newimc, 0); 645 ok(rc, "ImmAssociateContextEx failed\n"); 646 retimc = ImmGetContext(hwnd); 647 ok(retimc == newimc, "handles should be the same\n"); 648 ImmReleaseContext(hwnd,retimc); 649 650 rc = pImmAssociateContextEx(hwnd, NULL, IACE_DEFAULT); 651 ok(rc, "ImmAssociateContextEx failed\n"); 652 } 653 ImmReleaseContext(hwnd,imc); 654 } 655 656 typedef struct _igc_threadinfo { 657 HWND hwnd; 658 HANDLE event; 659 HIMC himc; 660 HIMC u_himc; 661 } igc_threadinfo; 662 663 664 static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam) 665 { 666 HIMC h1,h2; 667 HWND hwnd2; 668 COMPOSITIONFORM cf; 669 CANDIDATEFORM cdf; 670 POINT pt; 671 MSG msg; 672 673 igc_threadinfo *info= (igc_threadinfo*)lpParam; 674 info->hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 675 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 676 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 677 678 h1 = ImmGetContext(hwnd); 679 ok(info->himc == h1, "hwnd context changed in new thread\n"); 680 h2 = ImmGetContext(info->hwnd); 681 ok(h2 != h1, "new hwnd in new thread should have different context\n"); 682 info->himc = h2; 683 ImmReleaseContext(hwnd,h1); 684 685 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 686 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 687 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 688 h1 = ImmGetContext(hwnd2); 689 690 ok(h1 == h2, "Windows in same thread should have same default context\n"); 691 ImmReleaseContext(hwnd2,h1); 692 ImmReleaseContext(info->hwnd,h2); 693 DestroyWindow(hwnd2); 694 695 /* priming for later tests */ 696 ImmSetCompositionWindow(h1, &cf); 697 ImmSetStatusWindowPos(h1, &pt); 698 info->u_himc = ImmCreateContext(); 699 ImmSetOpenStatus(info->u_himc, TRUE); 700 cdf.dwIndex = 0; 701 cdf.dwStyle = CFS_CANDIDATEPOS; 702 cdf.ptCurrentPos.x = 0; 703 cdf.ptCurrentPos.y = 0; 704 ImmSetCandidateWindow(info->u_himc, &cdf); 705 706 SetEvent(info->event); 707 708 while(GetMessageW(&msg, 0, 0, 0)) 709 { 710 TranslateMessage(&msg); 711 DispatchMessageW(&msg); 712 } 713 return 1; 714 } 715 716 static void test_ImmThreads(void) 717 { 718 HIMC himc, otherHimc, h1; 719 igc_threadinfo threadinfo; 720 HANDLE hThread; 721 DWORD dwThreadId; 722 BOOL rc; 723 LOGFONTA lf; 724 COMPOSITIONFORM cf; 725 CANDIDATEFORM cdf; 726 DWORD status, sentence; 727 POINT pt; 728 729 himc = ImmGetContext(hwnd); 730 threadinfo.event = CreateEventA(NULL, TRUE, FALSE, NULL); 731 threadinfo.himc = himc; 732 hThread = CreateThread(NULL, 0, ImmGetContextThreadFunc, &threadinfo, 0, &dwThreadId ); 733 WaitForSingleObject(threadinfo.event, INFINITE); 734 735 otherHimc = ImmGetContext(threadinfo.hwnd); 736 737 ok(himc != otherHimc, "Windows from other threads should have different himc\n"); 738 ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n"); 739 740 h1 = ImmAssociateContext(hwnd,otherHimc); 741 ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n"); 742 h1 = ImmGetContext(hwnd); 743 ok(h1 == himc, "Context for window should remain unchanged\n"); 744 ImmReleaseContext(hwnd,h1); 745 746 h1 = ImmAssociateContext(hwnd, threadinfo.u_himc); 747 ok (h1 == NULL, "Should fail to associate a context from a different thread\n"); 748 h1 = ImmGetContext(hwnd); 749 ok(h1 == himc, "Context for window should remain unchanged\n"); 750 ImmReleaseContext(hwnd,h1); 751 752 h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc); 753 ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n"); 754 h1 = ImmGetContext(threadinfo.hwnd); 755 ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n"); 756 ImmReleaseContext(threadinfo.hwnd,h1); 757 758 /* OpenStatus */ 759 rc = ImmSetOpenStatus(himc, TRUE); 760 ok(rc != 0, "ImmSetOpenStatus failed\n"); 761 rc = ImmGetOpenStatus(himc); 762 ok(rc != 0, "ImmGetOpenStatus failed\n"); 763 rc = ImmSetOpenStatus(himc, FALSE); 764 ok(rc != 0, "ImmSetOpenStatus failed\n"); 765 rc = ImmGetOpenStatus(himc); 766 ok(rc == 0, "ImmGetOpenStatus failed\n"); 767 768 rc = ImmSetOpenStatus(otherHimc, TRUE); 769 ok(rc == 0, "ImmSetOpenStatus should fail\n"); 770 rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE); 771 ok(rc == 0, "ImmSetOpenStatus should fail\n"); 772 rc = ImmGetOpenStatus(otherHimc); 773 ok(rc == 0, "ImmGetOpenStatus failed\n"); 774 rc = ImmGetOpenStatus(threadinfo.u_himc); 775 ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n"); 776 rc = ImmSetOpenStatus(otherHimc, FALSE); 777 ok(rc == 0, "ImmSetOpenStatus should fail\n"); 778 rc = ImmGetOpenStatus(otherHimc); 779 ok(rc == 0, "ImmGetOpenStatus failed\n"); 780 781 /* CompositionFont */ 782 rc = ImmGetCompositionFontA(himc, &lf); 783 ok(rc != 0, "ImmGetCompositionFont failed\n"); 784 rc = ImmSetCompositionFontA(himc, &lf); 785 ok(rc != 0, "ImmSetCompositionFont failed\n"); 786 787 rc = ImmGetCompositionFontA(otherHimc, &lf); 788 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n"); 789 rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf); 790 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n"); 791 rc = ImmSetCompositionFontA(otherHimc, &lf); 792 ok(rc == 0, "ImmSetCompositionFont should fail\n"); 793 rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf); 794 ok(rc == 0, "ImmSetCompositionFont should fail\n"); 795 796 /* CompositionWindow */ 797 rc = ImmSetCompositionWindow(himc, &cf); 798 ok(rc != 0, "ImmSetCompositionWindow failed\n"); 799 rc = ImmGetCompositionWindow(himc, &cf); 800 ok(rc != 0, "ImmGetCompositionWindow failed\n"); 801 802 rc = ImmSetCompositionWindow(otherHimc, &cf); 803 ok(rc == 0, "ImmSetCompositionWindow should fail\n"); 804 rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf); 805 ok(rc == 0, "ImmSetCompositionWindow should fail\n"); 806 rc = ImmGetCompositionWindow(otherHimc, &cf); 807 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); 808 rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf); 809 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); 810 811 /* ConversionStatus */ 812 rc = ImmGetConversionStatus(himc, &status, &sentence); 813 ok(rc != 0, "ImmGetConversionStatus failed\n"); 814 rc = ImmSetConversionStatus(himc, status, sentence); 815 ok(rc != 0, "ImmSetConversionStatus failed\n"); 816 817 rc = ImmGetConversionStatus(otherHimc, &status, &sentence); 818 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); 819 rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence); 820 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); 821 rc = ImmSetConversionStatus(otherHimc, status, sentence); 822 ok(rc == 0, "ImmSetConversionStatus should fail\n"); 823 rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence); 824 ok(rc == 0, "ImmSetConversionStatus should fail\n"); 825 826 /* StatusWindowPos */ 827 rc = ImmSetStatusWindowPos(himc, &pt); 828 ok(rc != 0, "ImmSetStatusWindowPos failed\n"); 829 rc = ImmGetStatusWindowPos(himc, &pt); 830 ok(rc != 0, "ImmGetStatusWindowPos failed\n"); 831 832 rc = ImmSetStatusWindowPos(otherHimc, &pt); 833 ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); 834 rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt); 835 ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); 836 rc = ImmGetStatusWindowPos(otherHimc, &pt); 837 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); 838 rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt); 839 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); 840 841 h1 = ImmAssociateContext(threadinfo.hwnd, NULL); 842 ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n"); 843 h1 = ImmGetContext(threadinfo.hwnd); 844 ok (h1 == NULL, "CrossThread window context should be NULL\n"); 845 h1 = ImmAssociateContext(threadinfo.hwnd, h1); 846 ok (h1 == NULL, "Resetting cross thread context should fail\n"); 847 h1 = ImmGetContext(threadinfo.hwnd); 848 ok (h1 == NULL, "CrossThread window context should still be NULL\n"); 849 850 rc = ImmDestroyContext(threadinfo.u_himc); 851 ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n"); 852 853 /* Candidate Window */ 854 rc = ImmGetCandidateWindow(himc, 0, &cdf); 855 ok (rc == 0, "ImmGetCandidateWindow should fail\n"); 856 cdf.dwIndex = 0; 857 cdf.dwStyle = CFS_CANDIDATEPOS; 858 cdf.ptCurrentPos.x = 0; 859 cdf.ptCurrentPos.y = 0; 860 rc = ImmSetCandidateWindow(himc, &cdf); 861 ok (rc == 1, "ImmSetCandidateWindow should succeed\n"); 862 rc = ImmGetCandidateWindow(himc, 0, &cdf); 863 ok (rc == 1, "ImmGetCandidateWindow should succeed\n"); 864 865 rc = ImmGetCandidateWindow(otherHimc, 0, &cdf); 866 ok (rc == 0, "ImmGetCandidateWindow should fail\n"); 867 rc = ImmSetCandidateWindow(otherHimc, &cdf); 868 ok (rc == 0, "ImmSetCandidateWindow should fail\n"); 869 rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf); 870 ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n"); 871 rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf); 872 ok (rc == 0, "ImmSetCandidateWindow should fail\n"); 873 874 ImmReleaseContext(threadinfo.hwnd,otherHimc); 875 ImmReleaseContext(hwnd,himc); 876 877 SendMessageA(threadinfo.hwnd, WM_CLOSE, 0, 0); 878 rc = PostThreadMessageA(dwThreadId, WM_QUIT, 1, 0); 879 ok(rc == 1, "PostThreadMessage should succeed\n"); 880 WaitForSingleObject(hThread, INFINITE); 881 CloseHandle(hThread); 882 883 himc = ImmGetContext(GetDesktopWindow()); 884 ok(himc == NULL, "Should not be able to get himc from other process window\n"); 885 } 886 887 static void test_ImmIsUIMessage(void) 888 { 889 struct test 890 { 891 UINT msg; 892 BOOL ret; 893 }; 894 895 static const struct test tests[] = 896 { 897 { WM_MOUSEMOVE, FALSE }, 898 { WM_IME_STARTCOMPOSITION, TRUE }, 899 { WM_IME_ENDCOMPOSITION, TRUE }, 900 { WM_IME_COMPOSITION, TRUE }, 901 { WM_IME_SETCONTEXT, TRUE }, 902 { WM_IME_NOTIFY, TRUE }, 903 { WM_IME_CONTROL, FALSE }, 904 { WM_IME_COMPOSITIONFULL, TRUE }, 905 { WM_IME_SELECT, TRUE }, 906 { WM_IME_CHAR, FALSE }, 907 { 0x287 /* FIXME */, TRUE }, 908 { WM_IME_REQUEST, FALSE }, 909 { WM_IME_KEYDOWN, FALSE }, 910 { WM_IME_KEYUP, FALSE }, 911 { 0, FALSE } /* mark the end */ 912 }; 913 914 UINT WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService"); 915 UINT WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions"); 916 UINT WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation"); 917 UINT WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest"); 918 UINT WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert"); 919 UINT WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition"); 920 UINT WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed"); 921 922 const struct test *test; 923 BOOL ret; 924 925 if (!pImmIsUIMessageA) return; 926 927 for (test = tests; test->msg; test++) 928 { 929 msg_spy_flush_msgs(); 930 ret = pImmIsUIMessageA(NULL, test->msg, 0, 0); 931 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg); 932 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x for NULL hwnd\n", test->msg); 933 934 ret = pImmIsUIMessageA(hwnd, test->msg, 0, 0); 935 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg); 936 if (ret) 937 ok(msg_spy_find_msg(test->msg) != NULL, "Windows does send 0x%x\n", test->msg); 938 else 939 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x\n", test->msg); 940 } 941 942 ret = pImmIsUIMessageA(NULL, WM_MSIME_SERVICE, 0, 0); 943 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n"); 944 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTOPTIONS, 0, 0); 945 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n"); 946 ret = pImmIsUIMessageA(NULL, WM_MSIME_MOUSE, 0, 0); 947 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n"); 948 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTREQUEST, 0, 0); 949 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n"); 950 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERT, 0, 0); 951 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n"); 952 ret = pImmIsUIMessageA(NULL, WM_MSIME_QUERYPOSITION, 0, 0); 953 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n"); 954 ret = pImmIsUIMessageA(NULL, WM_MSIME_DOCUMENTFEED, 0, 0); 955 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n"); 956 } 957 958 static void test_ImmGetContext(void) 959 { 960 HIMC himc; 961 DWORD err; 962 963 SetLastError(0xdeadbeef); 964 himc = ImmGetContext((HWND)0xffffffff); 965 err = GetLastError(); 966 ok(himc == NULL, "ImmGetContext succeeded\n"); 967 ok(err == ERROR_INVALID_WINDOW_HANDLE, "got %u\n", err); 968 969 himc = ImmGetContext(hwnd); 970 ok(himc != NULL, "ImmGetContext failed\n"); 971 ok(ImmReleaseContext(hwnd, himc), "ImmReleaseContext failed\n"); 972 } 973 974 static void test_ImmGetDescription(void) 975 { 976 HKL hkl; 977 WCHAR descW[100]; 978 CHAR descA[100]; 979 UINT ret, lret; 980 981 /* FIXME: invalid keyboard layouts should not pass */ 982 ret = ImmGetDescriptionW(NULL, NULL, 0); 983 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret); 984 ret = ImmGetDescriptionA(NULL, NULL, 0); 985 ok(!ret, "ImmGetDescriptionA failed, expected 0 received %d.\n", ret); 986 987 /* load a language with valid IMM descriptions */ 988 hkl = GetKeyboardLayout(0); 989 ok(hkl != 0, "GetKeyboardLayout failed, expected != 0.\n"); 990 991 ret = ImmGetDescriptionW(hkl, NULL, 0); 992 if(!ret) 993 { 994 win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n"); 995 return; 996 } 997 998 SetLastError(0xdeadcafe); 999 ret = ImmGetDescriptionW(0, NULL, 100); 1000 ok (ret == 0, "ImmGetDescriptionW with 0 hkl should return 0\n"); 1001 ret = GetLastError(); 1002 ok (ret == 0xdeadcafe, "Last Error should remain unchanged\n"); 1003 1004 ret = ImmGetDescriptionW(hkl, descW, 0); 1005 ok(ret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); 1006 1007 lret = ImmGetDescriptionW(hkl, descW, ret + 1); 1008 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); 1009 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); 1010 1011 lret = ImmGetDescriptionA(hkl, descA, ret + 1); 1012 ok(lret, "ImmGetDescriptionA failed, expected != 0 received 0.\n"); 1013 ok(lret == ret, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); 1014 1015 ret /= 2; /* try to copy partially */ 1016 lret = ImmGetDescriptionW(hkl, descW, ret + 1); 1017 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); 1018 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); 1019 1020 lret = ImmGetDescriptionA(hkl, descA, ret + 1); 1021 ok(!lret, "ImmGetDescriptionA should fail\n"); 1022 1023 ret = ImmGetDescriptionW(hkl, descW, 1); 1024 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret); 1025 1026 UnloadKeyboardLayout(hkl); 1027 } 1028 1029 static LRESULT (WINAPI *old_imm_wnd_proc)(HWND, UINT, WPARAM, LPARAM); 1030 static LRESULT WINAPI imm_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 1031 { 1032 ok(msg != WM_DESTROY, "got WM_DESTROY message\n"); 1033 return old_imm_wnd_proc(hwnd, msg, wparam, lparam); 1034 } 1035 1036 static HWND thread_ime_wnd; 1037 static DWORD WINAPI test_ImmGetDefaultIMEWnd_thread(void *arg) 1038 { 1039 CreateWindowA("static", "static", WS_POPUP, 0, 0, 1, 1, NULL, NULL, NULL, NULL); 1040 1041 thread_ime_wnd = ImmGetDefaultIMEWnd(0); 1042 ok(thread_ime_wnd != 0, "ImmGetDefaultIMEWnd returned NULL\n"); 1043 old_imm_wnd_proc = (void*)SetWindowLongPtrW(thread_ime_wnd, GWLP_WNDPROC, (LONG_PTR)imm_wnd_proc); 1044 return 0; 1045 } 1046 1047 static void test_ImmDefaultHwnd(void) 1048 { 1049 HIMC imc1, imc2, imc3; 1050 HWND def1, def3; 1051 HANDLE thread; 1052 HWND hwnd; 1053 char title[16]; 1054 LONG style; 1055 1056 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test", 1057 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1058 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1059 1060 ShowWindow(hwnd, SW_SHOWNORMAL); 1061 1062 imc1 = ImmGetContext(hwnd); 1063 if (!imc1) 1064 { 1065 win_skip("IME support not implemented\n"); 1066 return; 1067 } 1068 1069 def1 = ImmGetDefaultIMEWnd(hwnd); 1070 1071 GetWindowTextA(def1, title, sizeof(title)); 1072 ok(!strcmp(title, "Default IME"), "got %s\n", title); 1073 style = GetWindowLongA(def1, GWL_STYLE); 1074 ok(style == (WS_DISABLED | WS_POPUP | WS_CLIPSIBLINGS), "got %08x\n", style); 1075 style = GetWindowLongA(def1, GWL_EXSTYLE); 1076 ok(style == 0, "got %08x\n", style); 1077 1078 imc2 = ImmCreateContext(); 1079 ImmSetOpenStatus(imc2, TRUE); 1080 1081 imc3 = ImmGetContext(hwnd); 1082 def3 = ImmGetDefaultIMEWnd(hwnd); 1083 1084 ok(def3 == def1, "Default IME window should not change\n"); 1085 ok(imc1 == imc3, "IME context should not change\n"); 1086 ImmSetOpenStatus(imc2, FALSE); 1087 1088 thread = CreateThread(NULL, 0, test_ImmGetDefaultIMEWnd_thread, NULL, 0, NULL); 1089 WaitForSingleObject(thread, INFINITE); 1090 ok(thread_ime_wnd != def1, "thread_ime_wnd == def1\n"); 1091 ok(!IsWindow(thread_ime_wnd), "thread_ime_wnd was not destroyed\n"); 1092 CloseHandle(thread); 1093 1094 ImmReleaseContext(hwnd, imc1); 1095 ImmReleaseContext(hwnd, imc3); 1096 ImmDestroyContext(imc2); 1097 DestroyWindow(hwnd); 1098 } 1099 1100 static BOOL CALLBACK is_ime_window_proc(HWND hWnd, LPARAM param) 1101 { 1102 static const WCHAR imeW[] = {'I','M','E',0}; 1103 WCHAR class_nameW[16]; 1104 HWND *ime_window = (HWND *)param; 1105 if (GetClassNameW(hWnd, class_nameW, ARRAY_SIZE(class_nameW)) && !lstrcmpW(class_nameW, imeW)) 1106 { 1107 *ime_window = hWnd; 1108 return FALSE; 1109 } 1110 return TRUE; 1111 } 1112 1113 static HWND get_ime_window(void) 1114 { 1115 HWND ime_window = NULL; 1116 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc, (LPARAM)&ime_window); 1117 return ime_window; 1118 } 1119 1120 struct testcase_ime_window { 1121 BOOL visible; 1122 BOOL top_level_window; 1123 }; 1124 1125 static DWORD WINAPI test_default_ime_window_cb(void *arg) 1126 { 1127 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg; 1128 DWORD visible = testcase->visible ? WS_VISIBLE : 0; 1129 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd; 1130 1131 ok(!get_ime_window(), "Expected no IME windows\n"); 1132 if (testcase->top_level_window) { 1133 test_phase = FIRST_WINDOW; 1134 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1135 WS_OVERLAPPEDWINDOW | visible, 1136 CW_USEDEFAULT, CW_USEDEFAULT, 1137 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1138 } 1139 else { 1140 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test", 1141 WS_CHILD | visible, 1142 CW_USEDEFAULT, CW_USEDEFAULT, 1143 240, 24, hwnd, NULL, GetModuleHandleW(NULL), NULL); 1144 } 1145 ime_wnd = get_ime_window(); 1146 ok(ime_wnd != NULL, "Expected IME window existence\n"); 1147 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1148 ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd); 1149 1150 test_phase = SECOND_WINDOW; 1151 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1152 WS_OVERLAPPEDWINDOW | visible, 1153 CW_USEDEFAULT, CW_USEDEFAULT, 1154 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1155 DestroyWindow(hwnd2); 1156 ok(IsWindow(ime_wnd) || 1157 broken(!testcase->visible /* Vista */) || 1158 broken(!testcase->top_level_window /* Vista */) , 1159 "Expected IME window existence\n"); 1160 DestroyWindow(hwnd1); 1161 ok(!IsWindow(ime_wnd), "Expected no IME windows\n"); 1162 return 1; 1163 } 1164 1165 static DWORD WINAPI test_default_ime_window_cancel_cb(void *arg) 1166 { 1167 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg; 1168 DWORD visible = testcase->visible ? WS_VISIBLE : 0; 1169 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd; 1170 1171 ok(!get_ime_window(), "Expected no IME windows\n"); 1172 test_phase = NCCREATE_CANCEL; 1173 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1174 WS_OVERLAPPEDWINDOW | visible, 1175 CW_USEDEFAULT, CW_USEDEFAULT, 1176 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1177 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1); 1178 ok(!get_ime_window(), "Expected no IME windows\n"); 1179 1180 test_phase = CREATE_CANCEL; 1181 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1182 WS_OVERLAPPEDWINDOW | visible, 1183 CW_USEDEFAULT, CW_USEDEFAULT, 1184 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1185 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1); 1186 ok(!get_ime_window(), "Expected no IME windows\n"); 1187 1188 test_phase = FIRST_WINDOW; 1189 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1190 WS_OVERLAPPEDWINDOW | visible, 1191 CW_USEDEFAULT, CW_USEDEFAULT, 1192 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1193 ime_wnd = get_ime_window(); 1194 ok(ime_wnd != NULL, "Expected IME window existence\n"); 1195 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2); 1196 ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd); 1197 1198 DestroyWindow(hwnd2); 1199 ok(!IsWindow(ime_wnd), "Expected no IME windows\n"); 1200 return 1; 1201 } 1202 1203 static DWORD WINAPI test_default_ime_disabled_cb(void *arg) 1204 { 1205 HWND hWnd, default_ime_wnd; 1206 1207 ok(!get_ime_window(), "Expected no IME windows\n"); 1208 ImmDisableIME(GetCurrentThreadId()); 1209 test_phase = IME_DISABLED; 1210 hWnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1211 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 1212 CW_USEDEFAULT, CW_USEDEFAULT, 1213 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1214 default_ime_wnd = ImmGetDefaultIMEWnd(hWnd); 1215 ok(!default_ime_wnd, "Expected no IME windows\n"); 1216 DestroyWindow(hWnd); 1217 return 1; 1218 } 1219 1220 static DWORD WINAPI test_default_ime_with_message_only_window_cb(void *arg) 1221 { 1222 HWND hwnd1, hwnd2, default_ime_wnd; 1223 1224 test_phase = PHASE_UNKNOWN; 1225 hwnd1 = CreateWindowA(wndcls, "Wine imm32.dll test", 1226 WS_OVERLAPPEDWINDOW, 1227 CW_USEDEFAULT, CW_USEDEFAULT, 1228 240, 120, HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); 1229 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1230 ok(!IsWindow(default_ime_wnd), "Expected no IME windows, got %p\n", default_ime_wnd); 1231 1232 hwnd2 = CreateWindowA(wndcls, "Wine imm32.dll test", 1233 WS_OVERLAPPEDWINDOW, 1234 CW_USEDEFAULT, CW_USEDEFAULT, 1235 240, 120, hwnd1, NULL, GetModuleHandleW(NULL), NULL); 1236 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2); 1237 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n"); 1238 1239 DestroyWindow(hwnd2); 1240 DestroyWindow(hwnd1); 1241 1242 hwnd1 = CreateWindowA(wndcls, "Wine imm32.dll test", 1243 WS_OVERLAPPEDWINDOW, 1244 CW_USEDEFAULT, CW_USEDEFAULT, 1245 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1246 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1247 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n"); 1248 SetParent(hwnd1, HWND_MESSAGE); 1249 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1250 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n"); 1251 DestroyWindow(hwnd1); 1252 return 1; 1253 } 1254 1255 static void test_default_ime_window_creation(void) 1256 { 1257 HANDLE thread; 1258 size_t i; 1259 struct testcase_ime_window testcases[] = { 1260 /* visible, top-level window */ 1261 { TRUE, TRUE }, 1262 { FALSE, TRUE }, 1263 { TRUE, FALSE }, 1264 { FALSE, FALSE } 1265 }; 1266 1267 for (i = 0; i < ARRAY_SIZE(testcases); i++) 1268 { 1269 thread = CreateThread(NULL, 0, test_default_ime_window_cb, &testcases[i], 0, NULL); 1270 ok(thread != NULL, "CreateThread failed with error %u\n", GetLastError()); 1271 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1) 1272 { 1273 MSG msg; 1274 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) 1275 { 1276 TranslateMessage(&msg); 1277 DispatchMessageA(&msg); 1278 } 1279 } 1280 CloseHandle(thread); 1281 1282 if (testcases[i].top_level_window) 1283 { 1284 thread = CreateThread(NULL, 0, test_default_ime_window_cancel_cb, &testcases[i], 0, NULL); 1285 ok(thread != NULL, "CreateThread failed with error %u\n", GetLastError()); 1286 WaitForSingleObject(thread, INFINITE); 1287 CloseHandle(thread); 1288 } 1289 } 1290 1291 thread = CreateThread(NULL, 0, test_default_ime_disabled_cb, NULL, 0, NULL); 1292 WaitForSingleObject(thread, INFINITE); 1293 CloseHandle(thread); 1294 1295 thread = CreateThread(NULL, 0, test_default_ime_with_message_only_window_cb, NULL, 0, NULL); 1296 WaitForSingleObject(thread, INFINITE); 1297 CloseHandle(thread); 1298 1299 test_phase = PHASE_UNKNOWN; 1300 } 1301 1302 static void test_ImmGetIMCLockCount(void) 1303 { 1304 HIMC imc; 1305 DWORD count, ret, i; 1306 INPUTCONTEXT *ic; 1307 1308 imc = ImmCreateContext(); 1309 ImmDestroyContext(imc); 1310 SetLastError(0xdeadbeef); 1311 count = ImmGetIMCLockCount((HIMC)0xdeadcafe); 1312 ok(count == 0, "Invalid IMC should return 0\n"); 1313 ret = GetLastError(); 1314 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1315 SetLastError(0xdeadbeef); 1316 count = ImmGetIMCLockCount(0x00000000); 1317 ok(count == 0, "NULL IMC should return 0\n"); 1318 ret = GetLastError(); 1319 ok(ret == 0xdeadbeef, "Last Error should remain unchanged: %08x\n",ret); 1320 count = ImmGetIMCLockCount(imc); 1321 ok(count == 0, "Destroyed IMC should return 0\n"); 1322 ret = GetLastError(); 1323 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1324 1325 imc = ImmCreateContext(); 1326 count = ImmGetIMCLockCount(imc); 1327 ok(count == 0, "expect 0, returned %d\n", count); 1328 ic = ImmLockIMC(imc); 1329 ok(ic != NULL, "ImmLockIMC failed!\n"); 1330 count = ImmGetIMCLockCount(imc); 1331 ok(count == 1, "expect 1, returned %d\n", count); 1332 ret = ImmUnlockIMC(imc); 1333 ok(ret == TRUE, "expect TRUE, ret %d\n", ret); 1334 count = ImmGetIMCLockCount(imc); 1335 ok(count == 0, "expect 0, returned %d\n", count); 1336 ret = ImmUnlockIMC(imc); 1337 ok(ret == TRUE, "expect TRUE, ret %d\n", ret); 1338 count = ImmGetIMCLockCount(imc); 1339 ok(count == 0, "expect 0, returned %d\n", count); 1340 1341 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++) 1342 { 1343 ic = ImmLockIMC(imc); 1344 ok(ic != NULL, "ImmLockIMC failed!\n"); 1345 } 1346 count = ImmGetIMCLockCount(imc); 1347 todo_wine ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %d\n", count); 1348 1349 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++) 1350 ImmUnlockIMC(imc); 1351 count = ImmGetIMCLockCount(imc); 1352 todo_wine ok(count == 1, "expect 1, returned %d\n", count); 1353 ImmUnlockIMC(imc); 1354 count = ImmGetIMCLockCount(imc); 1355 todo_wine ok(count == 0, "expect 0, returned %d\n", count); 1356 1357 ImmDestroyContext(imc); 1358 } 1359 1360 static void test_ImmGetIMCCLockCount(void) 1361 { 1362 HIMCC imcc; 1363 DWORD count, g_count, i; 1364 BOOL ret; 1365 VOID *p; 1366 1367 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO)); 1368 count = ImmGetIMCCLockCount(imcc); 1369 ok(count == 0, "expect 0, returned %d\n", count); 1370 ImmLockIMCC(imcc); 1371 count = ImmGetIMCCLockCount(imcc); 1372 ok(count == 1, "expect 1, returned %d\n", count); 1373 ret = ImmUnlockIMCC(imcc); 1374 ok(ret == FALSE, "expect FALSE, ret %d\n", ret); 1375 count = ImmGetIMCCLockCount(imcc); 1376 ok(count == 0, "expect 0, returned %d\n", count); 1377 ret = ImmUnlockIMCC(imcc); 1378 ok(ret == FALSE, "expect FALSE, ret %d\n", ret); 1379 count = ImmGetIMCCLockCount(imcc); 1380 ok(count == 0, "expect 0, returned %d\n", count); 1381 1382 p = ImmLockIMCC(imcc); 1383 ok(GlobalHandle(p) == imcc, "expect %p, returned %p\n", imcc, GlobalHandle(p)); 1384 1385 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++) 1386 { 1387 ImmLockIMCC(imcc); 1388 count = ImmGetIMCCLockCount(imcc); 1389 g_count = GlobalFlags(imcc) & GMEM_LOCKCOUNT; 1390 ok(count == g_count, "count %d, g_count %d\n", count, g_count); 1391 } 1392 count = ImmGetIMCCLockCount(imcc); 1393 ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %d\n", count); 1394 1395 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++) 1396 GlobalUnlock(imcc); 1397 count = ImmGetIMCCLockCount(imcc); 1398 ok(count == 1, "expect 1, returned %d\n", count); 1399 GlobalUnlock(imcc); 1400 count = ImmGetIMCCLockCount(imcc); 1401 ok(count == 0, "expect 0, returned %d\n", count); 1402 1403 ImmDestroyIMCC(imcc); 1404 } 1405 1406 static void test_ImmDestroyContext(void) 1407 { 1408 HIMC imc; 1409 DWORD ret, count; 1410 INPUTCONTEXT *ic; 1411 1412 imc = ImmCreateContext(); 1413 count = ImmGetIMCLockCount(imc); 1414 ok(count == 0, "expect 0, returned %d\n", count); 1415 ic = ImmLockIMC(imc); 1416 ok(ic != NULL, "ImmLockIMC failed!\n"); 1417 count = ImmGetIMCLockCount(imc); 1418 ok(count == 1, "expect 1, returned %d\n", count); 1419 ret = ImmDestroyContext(imc); 1420 ok(ret == TRUE, "Destroy a locked IMC should success!\n"); 1421 ic = ImmLockIMC(imc); 1422 ok(ic == NULL, "Lock a destroyed IMC should fail!\n"); 1423 ret = ImmUnlockIMC(imc); 1424 ok(ret == FALSE, "Unlock a destroyed IMC should fail!\n"); 1425 count = ImmGetIMCLockCount(imc); 1426 ok(count == 0, "Get lock count of a destroyed IMC should return 0!\n"); 1427 SetLastError(0xdeadbeef); 1428 ret = ImmDestroyContext(imc); 1429 ok(ret == FALSE, "Destroy a destroyed IMC should fail!\n"); 1430 ret = GetLastError(); 1431 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1432 } 1433 1434 static void test_ImmDestroyIMCC(void) 1435 { 1436 HIMCC imcc; 1437 DWORD ret, count, size; 1438 VOID *p; 1439 1440 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO)); 1441 count = ImmGetIMCCLockCount(imcc); 1442 ok(count == 0, "expect 0, returned %d\n", count); 1443 p = ImmLockIMCC(imcc); 1444 ok(p != NULL, "ImmLockIMCC failed!\n"); 1445 count = ImmGetIMCCLockCount(imcc); 1446 ok(count == 1, "expect 1, returned %d\n", count); 1447 size = ImmGetIMCCSize(imcc); 1448 ok(size == sizeof(CANDIDATEINFO), "returned %d\n", size); 1449 p = ImmDestroyIMCC(imcc); 1450 ok(p == NULL, "Destroy a locked IMCC should success!\n"); 1451 p = ImmLockIMCC(imcc); 1452 ok(p == NULL, "Lock a destroyed IMCC should fail!\n"); 1453 ret = ImmUnlockIMCC(imcc); 1454 ok(ret == FALSE, "Unlock a destroyed IMCC should return FALSE!\n"); 1455 count = ImmGetIMCCLockCount(imcc); 1456 ok(count == 0, "Get lock count of a destroyed IMCC should return 0!\n"); 1457 size = ImmGetIMCCSize(imcc); 1458 ok(size == 0, "Get size of a destroyed IMCC should return 0!\n"); 1459 SetLastError(0xdeadbeef); 1460 p = ImmDestroyIMCC(imcc); 1461 ok(p != NULL, "returned NULL\n"); 1462 ret = GetLastError(); 1463 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1464 } 1465 1466 static void test_ImmMessages(void) 1467 { 1468 CANDIDATEFORM cf; 1469 imm_msgs *msg; 1470 HWND defwnd; 1471 HIMC imc; 1472 UINT idx = 0; 1473 1474 LPINPUTCONTEXT lpIMC; 1475 LPTRANSMSG lpTransMsg; 1476 1477 HWND hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test", 1478 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1479 240, 120, NULL, NULL, GetModuleHandleA(NULL), NULL); 1480 1481 ShowWindow(hwnd, SW_SHOWNORMAL); 1482 defwnd = ImmGetDefaultIMEWnd(hwnd); 1483 imc = ImmGetContext(hwnd); 1484 1485 ImmSetOpenStatus(imc, TRUE); 1486 msg_spy_flush_msgs(); 1487 SendMessageA(defwnd, WM_IME_CONTROL, IMC_GETCANDIDATEPOS, (LPARAM)&cf ); 1488 do 1489 { 1490 msg = msg_spy_find_next_msg(WM_IME_CONTROL,&idx); 1491 if (msg) ok(!msg->post, "Message should not be posted\n"); 1492 } while (msg); 1493 msg_spy_flush_msgs(); 1494 1495 lpIMC = ImmLockIMC(imc); 1496 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); 1497 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); 1498 lpTransMsg += lpIMC->dwNumMsgBuf; 1499 lpTransMsg->message = WM_IME_STARTCOMPOSITION; 1500 lpTransMsg->wParam = 0; 1501 lpTransMsg->lParam = 0; 1502 ImmUnlockIMCC(lpIMC->hMsgBuf); 1503 lpIMC->dwNumMsgBuf++; 1504 ImmUnlockIMC(imc); 1505 ImmGenerateMessage(imc); 1506 idx = 0; 1507 do 1508 { 1509 msg = msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION, &idx); 1510 if (msg) ok(!msg->post, "Message should not be posted\n"); 1511 } while (msg); 1512 msg_spy_flush_msgs(); 1513 1514 lpIMC = ImmLockIMC(imc); 1515 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); 1516 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); 1517 lpTransMsg += lpIMC->dwNumMsgBuf; 1518 lpTransMsg->message = WM_IME_COMPOSITION; 1519 lpTransMsg->wParam = 0; 1520 lpTransMsg->lParam = 0; 1521 ImmUnlockIMCC(lpIMC->hMsgBuf); 1522 lpIMC->dwNumMsgBuf++; 1523 ImmUnlockIMC(imc); 1524 ImmGenerateMessage(imc); 1525 idx = 0; 1526 do 1527 { 1528 msg = msg_spy_find_next_msg(WM_IME_COMPOSITION, &idx); 1529 if (msg) ok(!msg->post, "Message should not be posted\n"); 1530 } while (msg); 1531 msg_spy_flush_msgs(); 1532 1533 lpIMC = ImmLockIMC(imc); 1534 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); 1535 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); 1536 lpTransMsg += lpIMC->dwNumMsgBuf; 1537 lpTransMsg->message = WM_IME_ENDCOMPOSITION; 1538 lpTransMsg->wParam = 0; 1539 lpTransMsg->lParam = 0; 1540 ImmUnlockIMCC(lpIMC->hMsgBuf); 1541 lpIMC->dwNumMsgBuf++; 1542 ImmUnlockIMC(imc); 1543 ImmGenerateMessage(imc); 1544 idx = 0; 1545 do 1546 { 1547 msg = msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION, &idx); 1548 if (msg) ok(!msg->post, "Message should not be posted\n"); 1549 } while (msg); 1550 msg_spy_flush_msgs(); 1551 1552 ImmSetOpenStatus(imc, FALSE); 1553 ImmReleaseContext(hwnd, imc); 1554 DestroyWindow(hwnd); 1555 } 1556 1557 static LRESULT CALLBACK processkey_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam, 1558 LPARAM lParam ) 1559 { 1560 return DefWindowProcW(hWnd, msg, wParam, lParam); 1561 } 1562 1563 static void test_ime_processkey(void) 1564 { 1565 WCHAR classNameW[] = {'P','r','o','c','e','s','s', 'K','e','y','T','e','s','t','C','l','a','s','s',0}; 1566 WCHAR windowNameW[] = {'P','r','o','c','e','s','s', 'K','e','y',0}; 1567 1568 MSG msg; 1569 WNDCLASSW wclass; 1570 HANDLE hInstance = GetModuleHandleW(NULL); 1571 TEST_INPUT inputs[2]; 1572 HIMC imc; 1573 INT rc; 1574 HWND hWndTest; 1575 1576 wclass.lpszClassName = classNameW; 1577 wclass.style = CS_HREDRAW | CS_VREDRAW; 1578 wclass.lpfnWndProc = processkey_wnd_proc; 1579 wclass.hInstance = hInstance; 1580 wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); 1581 wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW); 1582 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 1583 wclass.lpszMenuName = 0; 1584 wclass.cbClsExtra = 0; 1585 wclass.cbWndExtra = 0; 1586 if(!RegisterClassW(&wclass)){ 1587 win_skip("Failed to register window.\n"); 1588 return; 1589 } 1590 1591 /* create the test window that will receive the keystrokes */ 1592 hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW, 1593 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100, 1594 NULL, NULL, hInstance, NULL); 1595 1596 ShowWindow(hWndTest, SW_SHOW); 1597 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); 1598 SetForegroundWindow(hWndTest); 1599 UpdateWindow(hWndTest); 1600 1601 imc = ImmGetContext(hWndTest); 1602 if (!imc) 1603 { 1604 win_skip("IME not supported\n"); 1605 DestroyWindow(hWndTest); 1606 return; 1607 } 1608 1609 rc = ImmSetOpenStatus(imc, TRUE); 1610 if (rc != TRUE) 1611 { 1612 win_skip("Unable to open IME\n"); 1613 ImmReleaseContext(hWndTest, imc); 1614 DestroyWindow(hWndTest); 1615 return; 1616 } 1617 1618 /* flush pending messages */ 1619 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); 1620 1621 SetFocus(hWndTest); 1622 1623 /* init input data that never changes */ 1624 inputs[1].type = inputs[0].type = INPUT_KEYBOARD; 1625 inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0; 1626 inputs[1].u.ki.time = inputs[0].u.ki.time = 0; 1627 1628 /* Pressing a key */ 1629 inputs[0].u.ki.wVk = 0x41; 1630 inputs[0].u.ki.wScan = 0x1e; 1631 inputs[0].u.ki.dwFlags = 0x0; 1632 1633 pSendInput(1, (INPUT*)inputs, sizeof(INPUT)); 1634 1635 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) { 1636 if(msg.message != WM_KEYDOWN) 1637 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1638 else 1639 { 1640 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n"); 1641 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1642 if(msg.wParam == VK_PROCESSKEY) 1643 trace("ProcessKey was correctly found\n"); 1644 } 1645 TranslateMessage(&msg); 1646 DispatchMessageW(&msg); 1647 } 1648 1649 inputs[0].u.ki.wVk = 0x41; 1650 inputs[0].u.ki.wScan = 0x1e; 1651 inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP; 1652 1653 pSendInput(1, (INPUT*)inputs, sizeof(INPUT)); 1654 1655 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) { 1656 if(msg.message != WM_KEYUP) 1657 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1658 else 1659 { 1660 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n"); 1661 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1662 ok(msg.wParam != VK_PROCESSKEY,"ProcessKey should still not be Found\n"); 1663 } 1664 TranslateMessage(&msg); 1665 DispatchMessageW(&msg); 1666 } 1667 1668 ImmReleaseContext(hWndTest, imc); 1669 ImmSetOpenStatus(imc, FALSE); 1670 DestroyWindow(hWndTest); 1671 } 1672 1673 static void test_InvalidIMC(void) 1674 { 1675 HIMC imc_destroy; 1676 HIMC imc_null = 0x00000000; 1677 HIMC imc_bad = (HIMC)0xdeadcafe; 1678 1679 HIMC imc1, imc2, oldimc; 1680 DWORD ret; 1681 DWORD count; 1682 CHAR buffer[1000]; 1683 INPUTCONTEXT *ic; 1684 LOGFONTA lf; 1685 1686 memset(&lf, 0, sizeof(lf)); 1687 1688 imc_destroy = ImmCreateContext(); 1689 ret = ImmDestroyContext(imc_destroy); 1690 ok(ret == TRUE, "Destroy an IMC should success!\n"); 1691 1692 /* Test associating destroyed imc */ 1693 imc1 = ImmGetContext(hwnd); 1694 SetLastError(0xdeadbeef); 1695 oldimc = ImmAssociateContext(hwnd, imc_destroy); 1696 ok(!oldimc, "Associating to a destroyed imc should fail!\n"); 1697 ret = GetLastError(); 1698 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1699 imc2 = ImmGetContext(hwnd); 1700 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2); 1701 1702 /* Test associating NULL imc, which is different from an invalid imc */ 1703 oldimc = ImmAssociateContext(hwnd, imc_null); 1704 ok(oldimc != NULL, "Associating to NULL imc should success!\n"); 1705 imc2 = ImmGetContext(hwnd); 1706 ok(!imc2, "expect NULL, returned %p\n", imc2); 1707 oldimc = ImmAssociateContext(hwnd, imc1); 1708 ok(!oldimc, "expect NULL, returned %p\n", oldimc); 1709 imc2 = ImmGetContext(hwnd); 1710 ok(imc2 == imc1, "imc should not changed! imc2 %p, imc1 %p\n", imc2, imc1); 1711 1712 /* Test associating invalid imc */ 1713 imc1 = ImmGetContext(hwnd); 1714 SetLastError(0xdeadbeef); 1715 oldimc = ImmAssociateContext(hwnd, imc_bad); 1716 ok(!oldimc, "Associating to a destroyed imc should fail!\n"); 1717 ret = GetLastError(); 1718 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1719 imc2 = ImmGetContext(hwnd); 1720 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2); 1721 1722 1723 /* Test ImmGetCandidateListA */ 1724 SetLastError(0xdeadbeef); 1725 ret = ImmGetCandidateListA(imc_bad, 0, NULL, 0); 1726 ok(ret == 0, "Bad IME should return 0\n"); 1727 ret = GetLastError(); 1728 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1729 SetLastError(0xdeadbeef); 1730 ret = ImmGetCandidateListA(imc_null, 0, NULL, 0); 1731 ok(ret == 0, "NULL IME should return 0\n"); 1732 ret = GetLastError(); 1733 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1734 SetLastError(0xdeadbeef); 1735 ret = ImmGetCandidateListA(imc_destroy, 0, NULL, 0); 1736 ok(ret == 0, "Destroyed IME should return 0\n"); 1737 ret = GetLastError(); 1738 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1739 1740 /* Test ImmGetCandidateListCountA*/ 1741 SetLastError(0xdeadbeef); 1742 ret = ImmGetCandidateListCountA(imc_bad,&count); 1743 ok(ret == 0, "Bad IME should return 0\n"); 1744 ret = GetLastError(); 1745 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1746 SetLastError(0xdeadbeef); 1747 ret = ImmGetCandidateListCountA(imc_null,&count); 1748 ok(ret == 0, "NULL IME should return 0\n"); 1749 ret = GetLastError(); 1750 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1751 SetLastError(0xdeadbeef); 1752 ret = ImmGetCandidateListCountA(imc_destroy,&count); 1753 ok(ret == 0, "Destroyed IME should return 0\n"); 1754 ret = GetLastError(); 1755 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1756 1757 /* Test ImmGetCandidateWindow */ 1758 SetLastError(0xdeadbeef); 1759 ret = ImmGetCandidateWindow(imc_bad, 0, (LPCANDIDATEFORM)buffer); 1760 ok(ret == 0, "Bad IME should return 0\n"); 1761 ret = GetLastError(); 1762 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1763 SetLastError(0xdeadbeef); 1764 ret = ImmGetCandidateWindow(imc_null, 0, (LPCANDIDATEFORM)buffer); 1765 ok(ret == 0, "NULL IME should return 0\n"); 1766 ret = GetLastError(); 1767 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1768 SetLastError(0xdeadbeef); 1769 ret = ImmGetCandidateWindow(imc_destroy, 0, (LPCANDIDATEFORM)buffer); 1770 ok(ret == 0, "Destroyed IME should return 0\n"); 1771 ret = GetLastError(); 1772 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1773 1774 /* Test ImmGetCompositionFontA */ 1775 SetLastError(0xdeadbeef); 1776 ret = ImmGetCompositionFontA(imc_bad, (LPLOGFONTA)buffer); 1777 ok(ret == 0, "Bad IME should return 0\n"); 1778 ret = GetLastError(); 1779 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1780 SetLastError(0xdeadbeef); 1781 ret = ImmGetCompositionFontA(imc_null, (LPLOGFONTA)buffer); 1782 ok(ret == 0, "NULL IME should return 0\n"); 1783 ret = GetLastError(); 1784 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1785 SetLastError(0xdeadbeef); 1786 ret = ImmGetCompositionFontA(imc_destroy, (LPLOGFONTA)buffer); 1787 ok(ret == 0, "Destroyed IME should return 0\n"); 1788 ret = GetLastError(); 1789 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1790 1791 /* Test ImmGetCompositionWindow */ 1792 SetLastError(0xdeadbeef); 1793 ret = ImmGetCompositionWindow(imc_bad, (LPCOMPOSITIONFORM)buffer); 1794 ok(ret == 0, "Bad IME should return 0\n"); 1795 ret = GetLastError(); 1796 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1797 SetLastError(0xdeadbeef); 1798 ret = ImmGetCompositionWindow(imc_null, (LPCOMPOSITIONFORM)buffer); 1799 ok(ret == 0, "NULL IME should return 0\n"); 1800 ret = GetLastError(); 1801 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1802 SetLastError(0xdeadbeef); 1803 ret = ImmGetCompositionWindow(imc_destroy, (LPCOMPOSITIONFORM)buffer); 1804 ok(ret == 0, "Destroyed IME should return 0\n"); 1805 ret = GetLastError(); 1806 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1807 1808 /* Test ImmGetCompositionStringA */ 1809 SetLastError(0xdeadbeef); 1810 ret = ImmGetCompositionStringA(imc_bad, GCS_COMPSTR, NULL, 0); 1811 ok(ret == 0, "Bad IME should return 0\n"); 1812 ret = GetLastError(); 1813 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1814 SetLastError(0xdeadbeef); 1815 ret = ImmGetCompositionStringA(imc_null, GCS_COMPSTR, NULL, 0); 1816 ok(ret == 0, "NULL IME should return 0\n"); 1817 ret = GetLastError(); 1818 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1819 SetLastError(0xdeadbeef); 1820 ret = ImmGetCompositionStringA(imc_destroy, GCS_COMPSTR, NULL, 0); 1821 ok(ret == 0, "Destroyed IME should return 0\n"); 1822 ret = GetLastError(); 1823 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1824 1825 /* Test ImmSetOpenStatus */ 1826 SetLastError(0xdeadbeef); 1827 ret = ImmSetOpenStatus(imc_bad, 1); 1828 ok(ret == 0, "Bad IME should return 0\n"); 1829 ret = GetLastError(); 1830 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1831 SetLastError(0xdeadbeef); 1832 ret = ImmSetOpenStatus(imc_null, 1); 1833 ok(ret == 0, "NULL IME should return 0\n"); 1834 ret = GetLastError(); 1835 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1836 SetLastError(0xdeadbeef); 1837 ret = ImmSetOpenStatus(imc_destroy, 1); 1838 ok(ret == 0, "Destroyed IME should return 0\n"); 1839 ret = GetLastError(); 1840 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1841 1842 /* Test ImmGetOpenStatus */ 1843 SetLastError(0xdeadbeef); 1844 ret = ImmGetOpenStatus(imc_bad); 1845 ok(ret == 0, "Bad IME should return 0\n"); 1846 ret = GetLastError(); 1847 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1848 SetLastError(0xdeadbeef); 1849 ret = ImmGetOpenStatus(imc_null); 1850 ok(ret == 0, "NULL IME should return 0\n"); 1851 ret = GetLastError(); 1852 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1853 SetLastError(0xdeadbeef); 1854 ret = ImmGetOpenStatus(imc_destroy); 1855 ok(ret == 0, "Destroyed IME should return 0\n"); 1856 ret = GetLastError(); 1857 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1858 1859 /* Test ImmGetStatusWindowPos */ 1860 SetLastError(0xdeadbeef); 1861 ret = ImmGetStatusWindowPos(imc_bad, NULL); 1862 ok(ret == 0, "Bad IME should return 0\n"); 1863 ret = GetLastError(); 1864 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1865 SetLastError(0xdeadbeef); 1866 ret = ImmGetStatusWindowPos(imc_null, NULL); 1867 ok(ret == 0, "NULL IME should return 0\n"); 1868 ret = GetLastError(); 1869 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1870 SetLastError(0xdeadbeef); 1871 ret = ImmGetStatusWindowPos(imc_destroy, NULL); 1872 ok(ret == 0, "Destroyed IME should return 0\n"); 1873 ret = GetLastError(); 1874 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1875 1876 /* Test ImmRequestMessageA */ 1877 SetLastError(0xdeadbeef); 1878 ret = ImmRequestMessageA(imc_bad, WM_CHAR, 0); 1879 ok(ret == 0, "Bad IME should return 0\n"); 1880 ret = GetLastError(); 1881 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1882 SetLastError(0xdeadbeef); 1883 ret = ImmRequestMessageA(imc_null, WM_CHAR, 0); 1884 ok(ret == 0, "NULL IME should return 0\n"); 1885 ret = GetLastError(); 1886 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1887 SetLastError(0xdeadbeef); 1888 ret = ImmRequestMessageA(imc_destroy, WM_CHAR, 0); 1889 ok(ret == 0, "Destroyed IME should return 0\n"); 1890 ret = GetLastError(); 1891 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1892 1893 /* Test ImmSetCompositionFontA */ 1894 SetLastError(0xdeadbeef); 1895 ret = ImmSetCompositionFontA(imc_bad, &lf); 1896 ok(ret == 0, "Bad IME should return 0\n"); 1897 ret = GetLastError(); 1898 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1899 SetLastError(0xdeadbeef); 1900 ret = ImmSetCompositionFontA(imc_null, &lf); 1901 ok(ret == 0, "NULL IME should return 0\n"); 1902 ret = GetLastError(); 1903 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1904 SetLastError(0xdeadbeef); 1905 ret = ImmSetCompositionFontA(imc_destroy, &lf); 1906 ok(ret == 0, "Destroyed IME should return 0\n"); 1907 ret = GetLastError(); 1908 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1909 1910 /* Test ImmSetCompositionWindow */ 1911 SetLastError(0xdeadbeef); 1912 ret = ImmSetCompositionWindow(imc_bad, NULL); 1913 ok(ret == 0, "Bad IME should return 0\n"); 1914 ret = GetLastError(); 1915 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1916 SetLastError(0xdeadbeef); 1917 ret = ImmSetCompositionWindow(imc_null, NULL); 1918 ok(ret == 0, "NULL IME should return 0\n"); 1919 ret = GetLastError(); 1920 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1921 SetLastError(0xdeadbeef); 1922 ret = ImmSetCompositionWindow(imc_destroy, NULL); 1923 ok(ret == 0, "Destroyed IME should return 0\n"); 1924 ret = GetLastError(); 1925 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1926 1927 /* Test ImmSetConversionStatus */ 1928 SetLastError(0xdeadbeef); 1929 ret = ImmSetConversionStatus(imc_bad, 0, 0); 1930 ok(ret == 0, "Bad IME should return 0\n"); 1931 ret = GetLastError(); 1932 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1933 SetLastError(0xdeadbeef); 1934 ret = ImmSetConversionStatus(imc_null, 0, 0); 1935 ok(ret == 0, "NULL IME should return 0\n"); 1936 ret = GetLastError(); 1937 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1938 SetLastError(0xdeadbeef); 1939 ret = ImmSetConversionStatus(imc_destroy, 0, 0); 1940 ok(ret == 0, "Destroyed IME should return 0\n"); 1941 ret = GetLastError(); 1942 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1943 1944 /* Test ImmSetStatusWindowPos */ 1945 SetLastError(0xdeadbeef); 1946 ret = ImmSetStatusWindowPos(imc_bad, 0); 1947 ok(ret == 0, "Bad IME should return 0\n"); 1948 ret = GetLastError(); 1949 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1950 SetLastError(0xdeadbeef); 1951 ret = ImmSetStatusWindowPos(imc_null, 0); 1952 ok(ret == 0, "NULL IME should return 0\n"); 1953 ret = GetLastError(); 1954 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1955 SetLastError(0xdeadbeef); 1956 ret = ImmSetStatusWindowPos(imc_destroy, 0); 1957 ok(ret == 0, "Destroyed IME should return 0\n"); 1958 ret = GetLastError(); 1959 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1960 1961 /* Test ImmGetImeMenuItemsA */ 1962 SetLastError(0xdeadbeef); 1963 ret = ImmGetImeMenuItemsA(imc_bad, 0, 0, NULL, NULL, 0); 1964 ok(ret == 0, "Bad IME should return 0\n"); 1965 ret = GetLastError(); 1966 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1967 SetLastError(0xdeadbeef); 1968 ret = ImmGetImeMenuItemsA(imc_null, 0, 0, NULL, NULL, 0); 1969 ok(ret == 0, "NULL IME should return 0\n"); 1970 ret = GetLastError(); 1971 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1972 SetLastError(0xdeadbeef); 1973 ret = ImmGetImeMenuItemsA(imc_destroy, 0, 0, NULL, NULL, 0); 1974 ok(ret == 0, "Destroyed IME should return 0\n"); 1975 ret = GetLastError(); 1976 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1977 1978 /* Test ImmLockIMC */ 1979 SetLastError(0xdeadbeef); 1980 ic = ImmLockIMC(imc_bad); 1981 ok(ic == 0, "Bad IME should return 0\n"); 1982 ret = GetLastError(); 1983 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1984 SetLastError(0xdeadbeef); 1985 ic = ImmLockIMC(imc_null); 1986 ok(ic == 0, "NULL IME should return 0\n"); 1987 ret = GetLastError(); 1988 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1989 SetLastError(0xdeadbeef); 1990 ic = ImmLockIMC(imc_destroy); 1991 ok(ic == 0, "Destroyed IME should return 0\n"); 1992 ret = GetLastError(); 1993 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1994 1995 /* Test ImmUnlockIMC */ 1996 SetLastError(0xdeadbeef); 1997 ret = ImmUnlockIMC(imc_bad); 1998 ok(ret == 0, "Bad IME should return 0\n"); 1999 ret = GetLastError(); 2000 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 2001 SetLastError(0xdeadbeef); 2002 ret = ImmUnlockIMC(imc_null); 2003 ok(ret == 0, "NULL IME should return 0\n"); 2004 ret = GetLastError(); 2005 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 2006 SetLastError(0xdeadbeef); 2007 ret = ImmUnlockIMC(imc_destroy); 2008 ok(ret == 0, "Destroyed IME should return 0\n"); 2009 ret = GetLastError(); 2010 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 2011 2012 /* Test ImmGenerateMessage */ 2013 SetLastError(0xdeadbeef); 2014 ret = ImmGenerateMessage(imc_bad); 2015 ok(ret == 0, "Bad IME should return 0\n"); 2016 ret = GetLastError(); 2017 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 2018 SetLastError(0xdeadbeef); 2019 ret = ImmGenerateMessage(imc_null); 2020 ok(ret == 0, "NULL IME should return 0\n"); 2021 ret = GetLastError(); 2022 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 2023 SetLastError(0xdeadbeef); 2024 ret = ImmGenerateMessage(imc_destroy); 2025 ok(ret == 0, "Destroyed IME should return 0\n"); 2026 ret = GetLastError(); 2027 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 2028 } 2029 2030 START_TEST(imm32) { 2031 if (init()) 2032 { 2033 test_ImmNotifyIME(); 2034 test_ImmGetCompositionString(); 2035 test_ImmSetCompositionString(); 2036 test_ImmIME(); 2037 test_ImmAssociateContextEx(); 2038 test_ImmThreads(); 2039 test_ImmIsUIMessage(); 2040 test_ImmGetContext(); 2041 test_ImmGetDescription(); 2042 test_ImmDefaultHwnd(); 2043 test_default_ime_window_creation(); 2044 test_ImmGetIMCLockCount(); 2045 test_ImmGetIMCCLockCount(); 2046 test_ImmDestroyContext(); 2047 test_ImmDestroyIMCC(); 2048 test_InvalidIMC(); 2049 msg_spy_cleanup(); 2050 /* Reinitialize the hooks to capture all windows */ 2051 msg_spy_init(NULL); 2052 test_ImmMessages(); 2053 msg_spy_cleanup(); 2054 if (pSendInput) 2055 test_ime_processkey(); 2056 else win_skip("SendInput is not available\n"); 2057 } 2058 cleanup(); 2059 } 2060