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 else 453 win_skip("Composition string isn't available\n"); 454 455 ImmReleaseContext(hwnd, imc); 456 457 /* Test composition results input by IMM API */ 458 prop = ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR); 459 if (!(prop & SCS_CAP_COMPSTR)) { 460 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */ 461 skip("This IME doesn't support SCS_SETSTR\n"); 462 } 463 else { 464 ime_composition_test.old_wnd_proc = 465 (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, 466 (LONG_PTR)test_ime_wnd_proc); 467 imc = ImmGetContext(hwnd); 468 msg_spy_flush_msgs(); 469 470 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, 471 string, sizeof(string), NULL,0); 472 ok(ret, "ImmSetCompositionStringW failed\n"); 473 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, 474 wstring, sizeof(wstring)); 475 if (wlen > 0) { 476 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 477 ok(ret, "ImmNotifyIME(CPS_COMPLETE) failed\n"); 478 msg_spy_flush_msgs(); 479 ok(ime_composition_test.catch_result_str, 480 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n"); 481 } 482 else 483 win_skip("Composition string isn't available\n"); 484 ImmReleaseContext(hwnd, imc); 485 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, 486 (LONG_PTR)ime_composition_test.old_wnd_proc); 487 msg_spy_flush_msgs(); 488 } 489 490 /* Test composition results input by hand */ 491 memset(&ime_composition_test, 0, sizeof(ime_composition_test)); 492 if (winetest_interactive) { 493 HWND hwndMain, hwndChild; 494 MSG msg; 495 const DWORD MY_TIMER = 0xcaffe; 496 497 hwndMain = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, 498 "IME composition test", 499 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 500 CW_USEDEFAULT, CW_USEDEFAULT, 320, 160, 501 NULL, NULL, GetModuleHandleA(NULL), NULL); 502 hwndChild = CreateWindowExA(0, "static", 503 "Input a DBCS character here using IME.", 504 WS_CHILD | WS_VISIBLE, 505 0, 0, 320, 100, hwndMain, NULL, 506 GetModuleHandleA(NULL), NULL); 507 508 ime_composition_test.old_wnd_proc = 509 (WNDPROC)SetWindowLongPtrA(hwndChild, GWLP_WNDPROC, 510 (LONG_PTR)test_ime_wnd_proc); 511 512 SetFocus(hwndChild); 513 514 ime_composition_test.timer_id = MY_TIMER; 515 ime_composition_test.start = GetTickCount(); 516 SetTimer(hwndChild, ime_composition_test.timer_id, 100, NULL); 517 while (GetMessageA(&msg, NULL, 0, 0)) { 518 TranslateMessage(&msg); 519 DispatchMessageA(&msg); 520 if (!IsWindow(hwndMain)) 521 break; 522 } 523 if (!ime_composition_test.catch_result_str) 524 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n"); 525 msg_spy_flush_msgs(); 526 } 527 } 528 529 static void test_ImmSetCompositionString(void) 530 { 531 HIMC imc; 532 BOOL ret; 533 534 SetLastError(0xdeadbeef); 535 imc = ImmGetContext(hwnd); 536 ok(imc != 0, "ImmGetContext() failed. Last error: %u\n", GetLastError()); 537 if (!imc) 538 return; 539 540 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 0, NULL, 0); 541 ok(broken(!ret) || 542 ret, /* Vista+ */ 543 "ImmSetCompositionStringW() failed.\n"); 544 545 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR, 546 NULL, 0, NULL, 0); 547 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 548 549 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGECLAUSE, 550 NULL, 0, NULL, 0); 551 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 552 553 ret = ImmSetCompositionStringW(imc, SCS_CHANGEATTR | SCS_CHANGECLAUSE, 554 NULL, 0, NULL, 0); 555 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 556 557 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR | SCS_CHANGECLAUSE, 558 NULL, 0, NULL, 0); 559 ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); 560 561 ImmReleaseContext(hwnd, imc); 562 } 563 564 static void test_ImmIME(void) 565 { 566 HIMC imc; 567 568 imc = ImmGetContext(hwnd); 569 if (imc) 570 { 571 BOOL rc; 572 rc = ImmConfigureIMEA(imc, NULL, IME_CONFIG_REGISTERWORD, NULL); 573 ok (rc == 0, "ImmConfigureIMEA did not fail\n"); 574 rc = ImmConfigureIMEW(imc, NULL, IME_CONFIG_REGISTERWORD, NULL); 575 ok (rc == 0, "ImmConfigureIMEW did not fail\n"); 576 } 577 ImmReleaseContext(hwnd,imc); 578 } 579 580 static void test_ImmAssociateContextEx(void) 581 { 582 HIMC imc; 583 BOOL rc; 584 585 if (!pImmAssociateContextEx) return; 586 587 imc = ImmGetContext(hwnd); 588 if (imc) 589 { 590 HIMC retimc, newimc; 591 592 newimc = ImmCreateContext(); 593 ok(newimc != imc, "handles should not be the same\n"); 594 rc = pImmAssociateContextEx(NULL, NULL, 0); 595 ok(!rc, "ImmAssociateContextEx succeeded\n"); 596 rc = pImmAssociateContextEx(hwnd, NULL, 0); 597 ok(rc, "ImmAssociateContextEx failed\n"); 598 rc = pImmAssociateContextEx(NULL, imc, 0); 599 ok(!rc, "ImmAssociateContextEx succeeded\n"); 600 601 rc = pImmAssociateContextEx(hwnd, imc, 0); 602 ok(rc, "ImmAssociateContextEx failed\n"); 603 retimc = ImmGetContext(hwnd); 604 ok(retimc == imc, "handles should be the same\n"); 605 ImmReleaseContext(hwnd,retimc); 606 607 rc = pImmAssociateContextEx(hwnd, newimc, 0); 608 ok(rc, "ImmAssociateContextEx failed\n"); 609 retimc = ImmGetContext(hwnd); 610 ok(retimc == newimc, "handles should be the same\n"); 611 ImmReleaseContext(hwnd,retimc); 612 613 rc = pImmAssociateContextEx(hwnd, NULL, IACE_DEFAULT); 614 ok(rc, "ImmAssociateContextEx failed\n"); 615 } 616 ImmReleaseContext(hwnd,imc); 617 } 618 619 typedef struct _igc_threadinfo { 620 HWND hwnd; 621 HANDLE event; 622 HIMC himc; 623 HIMC u_himc; 624 } igc_threadinfo; 625 626 627 static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam) 628 { 629 HIMC h1,h2; 630 HWND hwnd2; 631 COMPOSITIONFORM cf; 632 CANDIDATEFORM cdf; 633 POINT pt; 634 MSG msg; 635 636 igc_threadinfo *info= (igc_threadinfo*)lpParam; 637 info->hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 638 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 639 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 640 641 h1 = ImmGetContext(hwnd); 642 ok(info->himc == h1, "hwnd context changed in new thread\n"); 643 h2 = ImmGetContext(info->hwnd); 644 ok(h2 != h1, "new hwnd in new thread should have different context\n"); 645 info->himc = h2; 646 ImmReleaseContext(hwnd,h1); 647 648 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 649 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 650 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 651 h1 = ImmGetContext(hwnd2); 652 653 ok(h1 == h2, "Windows in same thread should have same default context\n"); 654 ImmReleaseContext(hwnd2,h1); 655 ImmReleaseContext(info->hwnd,h2); 656 DestroyWindow(hwnd2); 657 658 /* priming for later tests */ 659 ImmSetCompositionWindow(h1, &cf); 660 ImmSetStatusWindowPos(h1, &pt); 661 info->u_himc = ImmCreateContext(); 662 ImmSetOpenStatus(info->u_himc, TRUE); 663 cdf.dwIndex = 0; 664 cdf.dwStyle = CFS_CANDIDATEPOS; 665 cdf.ptCurrentPos.x = 0; 666 cdf.ptCurrentPos.y = 0; 667 ImmSetCandidateWindow(info->u_himc, &cdf); 668 669 SetEvent(info->event); 670 671 while(GetMessageW(&msg, 0, 0, 0)) 672 { 673 TranslateMessage(&msg); 674 DispatchMessageW(&msg); 675 } 676 return 1; 677 } 678 679 static void test_ImmThreads(void) 680 { 681 HIMC himc, otherHimc, h1; 682 igc_threadinfo threadinfo; 683 HANDLE hThread; 684 DWORD dwThreadId; 685 BOOL rc; 686 LOGFONTA lf; 687 COMPOSITIONFORM cf; 688 CANDIDATEFORM cdf; 689 DWORD status, sentence; 690 POINT pt; 691 692 himc = ImmGetContext(hwnd); 693 threadinfo.event = CreateEventA(NULL, TRUE, FALSE, NULL); 694 threadinfo.himc = himc; 695 hThread = CreateThread(NULL, 0, ImmGetContextThreadFunc, &threadinfo, 0, &dwThreadId ); 696 WaitForSingleObject(threadinfo.event, INFINITE); 697 698 otherHimc = ImmGetContext(threadinfo.hwnd); 699 700 ok(himc != otherHimc, "Windows from other threads should have different himc\n"); 701 ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n"); 702 703 h1 = ImmAssociateContext(hwnd,otherHimc); 704 ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n"); 705 h1 = ImmGetContext(hwnd); 706 ok(h1 == himc, "Context for window should remain unchanged\n"); 707 ImmReleaseContext(hwnd,h1); 708 709 h1 = ImmAssociateContext(hwnd, threadinfo.u_himc); 710 ok (h1 == NULL, "Should fail to associate a context from a different thread\n"); 711 h1 = ImmGetContext(hwnd); 712 ok(h1 == himc, "Context for window should remain unchanged\n"); 713 ImmReleaseContext(hwnd,h1); 714 715 h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc); 716 ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n"); 717 h1 = ImmGetContext(threadinfo.hwnd); 718 ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n"); 719 ImmReleaseContext(threadinfo.hwnd,h1); 720 721 /* OpenStatus */ 722 rc = ImmSetOpenStatus(himc, TRUE); 723 ok(rc != 0, "ImmSetOpenStatus failed\n"); 724 rc = ImmGetOpenStatus(himc); 725 ok(rc != 0, "ImmGetOpenStatus failed\n"); 726 rc = ImmSetOpenStatus(himc, FALSE); 727 ok(rc != 0, "ImmSetOpenStatus failed\n"); 728 rc = ImmGetOpenStatus(himc); 729 ok(rc == 0, "ImmGetOpenStatus failed\n"); 730 731 rc = ImmSetOpenStatus(otherHimc, TRUE); 732 ok(rc == 0, "ImmSetOpenStatus should fail\n"); 733 rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE); 734 ok(rc == 0, "ImmSetOpenStatus should fail\n"); 735 rc = ImmGetOpenStatus(otherHimc); 736 ok(rc == 0, "ImmGetOpenStatus failed\n"); 737 rc = ImmGetOpenStatus(threadinfo.u_himc); 738 ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n"); 739 rc = ImmSetOpenStatus(otherHimc, FALSE); 740 ok(rc == 0, "ImmSetOpenStatus should fail\n"); 741 rc = ImmGetOpenStatus(otherHimc); 742 ok(rc == 0, "ImmGetOpenStatus failed\n"); 743 744 /* CompositionFont */ 745 rc = ImmGetCompositionFontA(himc, &lf); 746 ok(rc != 0, "ImmGetCompositionFont failed\n"); 747 rc = ImmSetCompositionFontA(himc, &lf); 748 ok(rc != 0, "ImmSetCompositionFont failed\n"); 749 750 rc = ImmGetCompositionFontA(otherHimc, &lf); 751 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n"); 752 rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf); 753 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n"); 754 rc = ImmSetCompositionFontA(otherHimc, &lf); 755 ok(rc == 0, "ImmSetCompositionFont should fail\n"); 756 rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf); 757 ok(rc == 0, "ImmSetCompositionFont should fail\n"); 758 759 /* CompositionWindow */ 760 rc = ImmSetCompositionWindow(himc, &cf); 761 ok(rc != 0, "ImmSetCompositionWindow failed\n"); 762 rc = ImmGetCompositionWindow(himc, &cf); 763 ok(rc != 0, "ImmGetCompositionWindow failed\n"); 764 765 rc = ImmSetCompositionWindow(otherHimc, &cf); 766 ok(rc == 0, "ImmSetCompositionWindow should fail\n"); 767 rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf); 768 ok(rc == 0, "ImmSetCompositionWindow should fail\n"); 769 rc = ImmGetCompositionWindow(otherHimc, &cf); 770 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); 771 rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf); 772 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); 773 774 /* ConversionStatus */ 775 rc = ImmGetConversionStatus(himc, &status, &sentence); 776 ok(rc != 0, "ImmGetConversionStatus failed\n"); 777 rc = ImmSetConversionStatus(himc, status, sentence); 778 ok(rc != 0, "ImmSetConversionStatus failed\n"); 779 780 rc = ImmGetConversionStatus(otherHimc, &status, &sentence); 781 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); 782 rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence); 783 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); 784 rc = ImmSetConversionStatus(otherHimc, status, sentence); 785 ok(rc == 0, "ImmSetConversionStatus should fail\n"); 786 rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence); 787 ok(rc == 0, "ImmSetConversionStatus should fail\n"); 788 789 /* StatusWindowPos */ 790 rc = ImmSetStatusWindowPos(himc, &pt); 791 ok(rc != 0, "ImmSetStatusWindowPos failed\n"); 792 rc = ImmGetStatusWindowPos(himc, &pt); 793 ok(rc != 0, "ImmGetStatusWindowPos failed\n"); 794 795 rc = ImmSetStatusWindowPos(otherHimc, &pt); 796 ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); 797 rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt); 798 ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); 799 rc = ImmGetStatusWindowPos(otherHimc, &pt); 800 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); 801 rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt); 802 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); 803 804 h1 = ImmAssociateContext(threadinfo.hwnd, NULL); 805 ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n"); 806 h1 = ImmGetContext(threadinfo.hwnd); 807 ok (h1 == NULL, "CrossThread window context should be NULL\n"); 808 h1 = ImmAssociateContext(threadinfo.hwnd, h1); 809 ok (h1 == NULL, "Resetting cross thread context should fail\n"); 810 h1 = ImmGetContext(threadinfo.hwnd); 811 ok (h1 == NULL, "CrossThread window context should still be NULL\n"); 812 813 rc = ImmDestroyContext(threadinfo.u_himc); 814 ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n"); 815 816 /* Candidate Window */ 817 rc = ImmGetCandidateWindow(himc, 0, &cdf); 818 ok (rc == 0, "ImmGetCandidateWindow should fail\n"); 819 cdf.dwIndex = 0; 820 cdf.dwStyle = CFS_CANDIDATEPOS; 821 cdf.ptCurrentPos.x = 0; 822 cdf.ptCurrentPos.y = 0; 823 rc = ImmSetCandidateWindow(himc, &cdf); 824 ok (rc == 1, "ImmSetCandidateWindow should succeed\n"); 825 rc = ImmGetCandidateWindow(himc, 0, &cdf); 826 ok (rc == 1, "ImmGetCandidateWindow should succeed\n"); 827 828 rc = ImmGetCandidateWindow(otherHimc, 0, &cdf); 829 ok (rc == 0, "ImmGetCandidateWindow should fail\n"); 830 rc = ImmSetCandidateWindow(otherHimc, &cdf); 831 ok (rc == 0, "ImmSetCandidateWindow should fail\n"); 832 rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf); 833 ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n"); 834 rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf); 835 ok (rc == 0, "ImmSetCandidateWindow should fail\n"); 836 837 ImmReleaseContext(threadinfo.hwnd,otherHimc); 838 ImmReleaseContext(hwnd,himc); 839 840 SendMessageA(threadinfo.hwnd, WM_CLOSE, 0, 0); 841 rc = PostThreadMessageA(dwThreadId, WM_QUIT, 1, 0); 842 ok(rc == 1, "PostThreadMessage should succeed\n"); 843 WaitForSingleObject(hThread, INFINITE); 844 CloseHandle(hThread); 845 846 himc = ImmGetContext(GetDesktopWindow()); 847 ok(himc == NULL, "Should not be able to get himc from other process window\n"); 848 } 849 850 static void test_ImmIsUIMessage(void) 851 { 852 struct test 853 { 854 UINT msg; 855 BOOL ret; 856 }; 857 858 static const struct test tests[] = 859 { 860 { WM_MOUSEMOVE, FALSE }, 861 { WM_IME_STARTCOMPOSITION, TRUE }, 862 { WM_IME_ENDCOMPOSITION, TRUE }, 863 { WM_IME_COMPOSITION, TRUE }, 864 { WM_IME_SETCONTEXT, TRUE }, 865 { WM_IME_NOTIFY, TRUE }, 866 { WM_IME_CONTROL, FALSE }, 867 { WM_IME_COMPOSITIONFULL, TRUE }, 868 { WM_IME_SELECT, TRUE }, 869 { WM_IME_CHAR, FALSE }, 870 { 0x287 /* FIXME */, TRUE }, 871 { WM_IME_REQUEST, FALSE }, 872 { WM_IME_KEYDOWN, FALSE }, 873 { WM_IME_KEYUP, FALSE }, 874 { 0, FALSE } /* mark the end */ 875 }; 876 877 UINT WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService"); 878 UINT WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions"); 879 UINT WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation"); 880 UINT WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest"); 881 UINT WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert"); 882 UINT WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition"); 883 UINT WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed"); 884 885 const struct test *test; 886 BOOL ret; 887 888 if (!pImmIsUIMessageA) return; 889 890 for (test = tests; test->msg; test++) 891 { 892 msg_spy_flush_msgs(); 893 ret = pImmIsUIMessageA(NULL, test->msg, 0, 0); 894 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg); 895 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x for NULL hwnd\n", test->msg); 896 897 ret = pImmIsUIMessageA(hwnd, test->msg, 0, 0); 898 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg); 899 if (ret) 900 ok(msg_spy_find_msg(test->msg) != NULL, "Windows does send 0x%x\n", test->msg); 901 else 902 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x\n", test->msg); 903 } 904 905 ret = pImmIsUIMessageA(NULL, WM_MSIME_SERVICE, 0, 0); 906 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n"); 907 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTOPTIONS, 0, 0); 908 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n"); 909 ret = pImmIsUIMessageA(NULL, WM_MSIME_MOUSE, 0, 0); 910 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n"); 911 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTREQUEST, 0, 0); 912 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n"); 913 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERT, 0, 0); 914 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n"); 915 ret = pImmIsUIMessageA(NULL, WM_MSIME_QUERYPOSITION, 0, 0); 916 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n"); 917 ret = pImmIsUIMessageA(NULL, WM_MSIME_DOCUMENTFEED, 0, 0); 918 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n"); 919 } 920 921 static void test_ImmGetContext(void) 922 { 923 HIMC himc; 924 DWORD err; 925 926 SetLastError(0xdeadbeef); 927 himc = ImmGetContext((HWND)0xffffffff); 928 err = GetLastError(); 929 ok(himc == NULL, "ImmGetContext succeeded\n"); 930 ok(err == ERROR_INVALID_WINDOW_HANDLE, "got %u\n", err); 931 932 himc = ImmGetContext(hwnd); 933 ok(himc != NULL, "ImmGetContext failed\n"); 934 ok(ImmReleaseContext(hwnd, himc), "ImmReleaseContext failed\n"); 935 } 936 937 static void test_ImmGetDescription(void) 938 { 939 HKL hkl; 940 WCHAR descW[100]; 941 CHAR descA[100]; 942 UINT ret, lret; 943 944 /* FIXME: invalid keyboard layouts should not pass */ 945 ret = ImmGetDescriptionW(NULL, NULL, 0); 946 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret); 947 ret = ImmGetDescriptionA(NULL, NULL, 0); 948 ok(!ret, "ImmGetDescriptionA failed, expected 0 received %d.\n", ret); 949 950 /* load a language with valid IMM descriptions */ 951 hkl = GetKeyboardLayout(0); 952 ok(hkl != 0, "GetKeyboardLayout failed, expected != 0.\n"); 953 954 ret = ImmGetDescriptionW(hkl, NULL, 0); 955 if(!ret) 956 { 957 win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n"); 958 return; 959 } 960 961 SetLastError(0xdeadcafe); 962 ret = ImmGetDescriptionW(0, NULL, 100); 963 ok (ret == 0, "ImmGetDescriptionW with 0 hkl should return 0\n"); 964 ret = GetLastError(); 965 ok (ret == 0xdeadcafe, "Last Error should remain unchanged\n"); 966 967 ret = ImmGetDescriptionW(hkl, descW, 0); 968 ok(ret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); 969 970 lret = ImmGetDescriptionW(hkl, descW, ret + 1); 971 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); 972 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); 973 974 lret = ImmGetDescriptionA(hkl, descA, ret + 1); 975 ok(lret, "ImmGetDescriptionA failed, expected != 0 received 0.\n"); 976 ok(lret == ret, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); 977 978 ret /= 2; /* try to copy partially */ 979 lret = ImmGetDescriptionW(hkl, descW, ret + 1); 980 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); 981 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); 982 983 lret = ImmGetDescriptionA(hkl, descA, ret + 1); 984 ok(!lret, "ImmGetDescriptionA should fail\n"); 985 986 ret = ImmGetDescriptionW(hkl, descW, 1); 987 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret); 988 989 UnloadKeyboardLayout(hkl); 990 } 991 992 static LRESULT (WINAPI *old_imm_wnd_proc)(HWND, UINT, WPARAM, LPARAM); 993 static LRESULT WINAPI imm_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 994 { 995 ok(msg != WM_DESTROY, "got WM_DESTROY message\n"); 996 return old_imm_wnd_proc(hwnd, msg, wparam, lparam); 997 } 998 999 static HWND thread_ime_wnd; 1000 static DWORD WINAPI test_ImmGetDefaultIMEWnd_thread(void *arg) 1001 { 1002 CreateWindowA("static", "static", WS_POPUP, 0, 0, 1, 1, NULL, NULL, NULL, NULL); 1003 1004 thread_ime_wnd = ImmGetDefaultIMEWnd(0); 1005 ok(thread_ime_wnd != 0, "ImmGetDefaultIMEWnd returned NULL\n"); 1006 old_imm_wnd_proc = (void*)SetWindowLongPtrW(thread_ime_wnd, GWLP_WNDPROC, (LONG_PTR)imm_wnd_proc); 1007 return 0; 1008 } 1009 1010 static void test_ImmDefaultHwnd(void) 1011 { 1012 HIMC imc1, imc2, imc3; 1013 HWND def1, def3; 1014 HANDLE thread; 1015 HWND hwnd; 1016 char title[16]; 1017 LONG style; 1018 1019 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test", 1020 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1021 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1022 1023 ShowWindow(hwnd, SW_SHOWNORMAL); 1024 1025 imc1 = ImmGetContext(hwnd); 1026 if (!imc1) 1027 { 1028 win_skip("IME support not implemented\n"); 1029 return; 1030 } 1031 1032 def1 = ImmGetDefaultIMEWnd(hwnd); 1033 1034 GetWindowTextA(def1, title, sizeof(title)); 1035 ok(!strcmp(title, "Default IME"), "got %s\n", title); 1036 style = GetWindowLongA(def1, GWL_STYLE); 1037 ok(style == (WS_DISABLED | WS_POPUP | WS_CLIPSIBLINGS), "got %08x\n", style); 1038 style = GetWindowLongA(def1, GWL_EXSTYLE); 1039 ok(style == 0, "got %08x\n", style); 1040 1041 imc2 = ImmCreateContext(); 1042 ImmSetOpenStatus(imc2, TRUE); 1043 1044 imc3 = ImmGetContext(hwnd); 1045 def3 = ImmGetDefaultIMEWnd(hwnd); 1046 1047 ok(def3 == def1, "Default IME window should not change\n"); 1048 ok(imc1 == imc3, "IME context should not change\n"); 1049 ImmSetOpenStatus(imc2, FALSE); 1050 1051 thread = CreateThread(NULL, 0, test_ImmGetDefaultIMEWnd_thread, NULL, 0, NULL); 1052 WaitForSingleObject(thread, INFINITE); 1053 ok(thread_ime_wnd != def1, "thread_ime_wnd == def1\n"); 1054 ok(!IsWindow(thread_ime_wnd), "thread_ime_wnd was not destroyed\n"); 1055 CloseHandle(thread); 1056 1057 ImmReleaseContext(hwnd, imc1); 1058 ImmReleaseContext(hwnd, imc3); 1059 ImmDestroyContext(imc2); 1060 DestroyWindow(hwnd); 1061 } 1062 1063 static BOOL CALLBACK is_ime_window_proc(HWND hWnd, LPARAM param) 1064 { 1065 static const WCHAR imeW[] = {'I','M','E',0}; 1066 WCHAR class_nameW[16]; 1067 HWND *ime_window = (HWND *)param; 1068 if (GetClassNameW(hWnd, class_nameW, ARRAY_SIZE(class_nameW)) && !lstrcmpW(class_nameW, imeW)) 1069 { 1070 *ime_window = hWnd; 1071 return FALSE; 1072 } 1073 return TRUE; 1074 } 1075 1076 static HWND get_ime_window(void) 1077 { 1078 HWND ime_window = NULL; 1079 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc, (LPARAM)&ime_window); 1080 return ime_window; 1081 } 1082 1083 struct testcase_ime_window { 1084 BOOL visible; 1085 BOOL top_level_window; 1086 }; 1087 1088 static DWORD WINAPI test_default_ime_window_cb(void *arg) 1089 { 1090 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg; 1091 DWORD visible = testcase->visible ? WS_VISIBLE : 0; 1092 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd; 1093 1094 ok(!get_ime_window(), "Expected no IME windows\n"); 1095 if (testcase->top_level_window) { 1096 test_phase = FIRST_WINDOW; 1097 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1098 WS_OVERLAPPEDWINDOW | visible, 1099 CW_USEDEFAULT, CW_USEDEFAULT, 1100 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1101 } 1102 else { 1103 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test", 1104 WS_CHILD | visible, 1105 CW_USEDEFAULT, CW_USEDEFAULT, 1106 240, 24, hwnd, NULL, GetModuleHandleW(NULL), NULL); 1107 } 1108 ime_wnd = get_ime_window(); 1109 ok(ime_wnd != NULL, "Expected IME window existence\n"); 1110 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1111 ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd); 1112 1113 test_phase = SECOND_WINDOW; 1114 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1115 WS_OVERLAPPEDWINDOW | visible, 1116 CW_USEDEFAULT, CW_USEDEFAULT, 1117 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1118 DestroyWindow(hwnd2); 1119 ok(IsWindow(ime_wnd) || 1120 broken(!testcase->visible /* Vista */) || 1121 broken(!testcase->top_level_window /* Vista */) , 1122 "Expected IME window existence\n"); 1123 DestroyWindow(hwnd1); 1124 ok(!IsWindow(ime_wnd), "Expected no IME windows\n"); 1125 return 1; 1126 } 1127 1128 static DWORD WINAPI test_default_ime_window_cancel_cb(void *arg) 1129 { 1130 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg; 1131 DWORD visible = testcase->visible ? WS_VISIBLE : 0; 1132 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd; 1133 1134 ok(!get_ime_window(), "Expected no IME windows\n"); 1135 test_phase = NCCREATE_CANCEL; 1136 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1137 WS_OVERLAPPEDWINDOW | visible, 1138 CW_USEDEFAULT, CW_USEDEFAULT, 1139 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1140 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1); 1141 ok(!get_ime_window(), "Expected no IME windows\n"); 1142 1143 test_phase = CREATE_CANCEL; 1144 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1145 WS_OVERLAPPEDWINDOW | visible, 1146 CW_USEDEFAULT, CW_USEDEFAULT, 1147 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1148 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1); 1149 ok(!get_ime_window(), "Expected no IME windows\n"); 1150 1151 test_phase = FIRST_WINDOW; 1152 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1153 WS_OVERLAPPEDWINDOW | visible, 1154 CW_USEDEFAULT, CW_USEDEFAULT, 1155 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1156 ime_wnd = get_ime_window(); 1157 ok(ime_wnd != NULL, "Expected IME window existence\n"); 1158 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2); 1159 ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd); 1160 1161 DestroyWindow(hwnd2); 1162 ok(!IsWindow(ime_wnd), "Expected no IME windows\n"); 1163 return 1; 1164 } 1165 1166 static DWORD WINAPI test_default_ime_disabled_cb(void *arg) 1167 { 1168 HWND hWnd, default_ime_wnd; 1169 1170 ok(!get_ime_window(), "Expected no IME windows\n"); 1171 ImmDisableIME(GetCurrentThreadId()); 1172 test_phase = IME_DISABLED; 1173 hWnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", 1174 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 1175 CW_USEDEFAULT, CW_USEDEFAULT, 1176 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1177 default_ime_wnd = ImmGetDefaultIMEWnd(hWnd); 1178 ok(!default_ime_wnd, "Expected no IME windows\n"); 1179 DestroyWindow(hWnd); 1180 return 1; 1181 } 1182 1183 static DWORD WINAPI test_default_ime_with_message_only_window_cb(void *arg) 1184 { 1185 HWND hwnd1, hwnd2, default_ime_wnd; 1186 1187 test_phase = PHASE_UNKNOWN; 1188 hwnd1 = CreateWindowA(wndcls, "Wine imm32.dll test", 1189 WS_OVERLAPPEDWINDOW, 1190 CW_USEDEFAULT, CW_USEDEFAULT, 1191 240, 120, HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); 1192 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1193 ok(!IsWindow(default_ime_wnd), "Expected no IME windows, got %p\n", default_ime_wnd); 1194 1195 hwnd2 = CreateWindowA(wndcls, "Wine imm32.dll test", 1196 WS_OVERLAPPEDWINDOW, 1197 CW_USEDEFAULT, CW_USEDEFAULT, 1198 240, 120, hwnd1, NULL, GetModuleHandleW(NULL), NULL); 1199 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2); 1200 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n"); 1201 1202 DestroyWindow(hwnd2); 1203 DestroyWindow(hwnd1); 1204 1205 hwnd1 = CreateWindowA(wndcls, "Wine imm32.dll test", 1206 WS_OVERLAPPEDWINDOW, 1207 CW_USEDEFAULT, CW_USEDEFAULT, 1208 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); 1209 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1210 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n"); 1211 SetParent(hwnd1, HWND_MESSAGE); 1212 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1); 1213 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n"); 1214 DestroyWindow(hwnd1); 1215 return 1; 1216 } 1217 1218 static void test_default_ime_window_creation(void) 1219 { 1220 HANDLE thread; 1221 size_t i; 1222 struct testcase_ime_window testcases[] = { 1223 /* visible, top-level window */ 1224 { TRUE, TRUE }, 1225 { FALSE, TRUE }, 1226 { TRUE, FALSE }, 1227 { FALSE, FALSE } 1228 }; 1229 1230 for (i = 0; i < ARRAY_SIZE(testcases); i++) 1231 { 1232 thread = CreateThread(NULL, 0, test_default_ime_window_cb, &testcases[i], 0, NULL); 1233 ok(thread != NULL, "CreateThread failed with error %u\n", GetLastError()); 1234 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1) 1235 { 1236 MSG msg; 1237 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) 1238 { 1239 TranslateMessage(&msg); 1240 DispatchMessageA(&msg); 1241 } 1242 } 1243 CloseHandle(thread); 1244 1245 if (testcases[i].top_level_window) 1246 { 1247 thread = CreateThread(NULL, 0, test_default_ime_window_cancel_cb, &testcases[i], 0, NULL); 1248 ok(thread != NULL, "CreateThread failed with error %u\n", GetLastError()); 1249 WaitForSingleObject(thread, INFINITE); 1250 CloseHandle(thread); 1251 } 1252 } 1253 1254 thread = CreateThread(NULL, 0, test_default_ime_disabled_cb, NULL, 0, NULL); 1255 WaitForSingleObject(thread, INFINITE); 1256 CloseHandle(thread); 1257 1258 thread = CreateThread(NULL, 0, test_default_ime_with_message_only_window_cb, NULL, 0, NULL); 1259 WaitForSingleObject(thread, INFINITE); 1260 CloseHandle(thread); 1261 1262 test_phase = PHASE_UNKNOWN; 1263 } 1264 1265 static void test_ImmGetIMCLockCount(void) 1266 { 1267 HIMC imc; 1268 DWORD count, ret, i; 1269 INPUTCONTEXT *ic; 1270 1271 imc = ImmCreateContext(); 1272 ImmDestroyContext(imc); 1273 SetLastError(0xdeadbeef); 1274 count = ImmGetIMCLockCount((HIMC)0xdeadcafe); 1275 ok(count == 0, "Invalid IMC should return 0\n"); 1276 ret = GetLastError(); 1277 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1278 SetLastError(0xdeadbeef); 1279 count = ImmGetIMCLockCount(0x00000000); 1280 ok(count == 0, "NULL IMC should return 0\n"); 1281 ret = GetLastError(); 1282 ok(ret == 0xdeadbeef, "Last Error should remain unchanged: %08x\n",ret); 1283 count = ImmGetIMCLockCount(imc); 1284 ok(count == 0, "Destroyed IMC should return 0\n"); 1285 ret = GetLastError(); 1286 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1287 1288 imc = ImmCreateContext(); 1289 count = ImmGetIMCLockCount(imc); 1290 ok(count == 0, "expect 0, returned %d\n", count); 1291 ic = ImmLockIMC(imc); 1292 ok(ic != NULL, "ImmLockIMC failed!\n"); 1293 count = ImmGetIMCLockCount(imc); 1294 ok(count == 1, "expect 1, returned %d\n", count); 1295 ret = ImmUnlockIMC(imc); 1296 ok(ret == TRUE, "expect TRUE, ret %d\n", ret); 1297 count = ImmGetIMCLockCount(imc); 1298 ok(count == 0, "expect 0, returned %d\n", count); 1299 ret = ImmUnlockIMC(imc); 1300 ok(ret == TRUE, "expect TRUE, ret %d\n", ret); 1301 count = ImmGetIMCLockCount(imc); 1302 ok(count == 0, "expect 0, returned %d\n", count); 1303 1304 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++) 1305 { 1306 ic = ImmLockIMC(imc); 1307 ok(ic != NULL, "ImmLockIMC failed!\n"); 1308 } 1309 count = ImmGetIMCLockCount(imc); 1310 todo_wine ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %d\n", count); 1311 1312 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++) 1313 ImmUnlockIMC(imc); 1314 count = ImmGetIMCLockCount(imc); 1315 todo_wine ok(count == 1, "expect 1, returned %d\n", count); 1316 ImmUnlockIMC(imc); 1317 count = ImmGetIMCLockCount(imc); 1318 todo_wine ok(count == 0, "expect 0, returned %d\n", count); 1319 1320 ImmDestroyContext(imc); 1321 } 1322 1323 static void test_ImmGetIMCCLockCount(void) 1324 { 1325 HIMCC imcc; 1326 DWORD count, g_count, i; 1327 BOOL ret; 1328 VOID *p; 1329 1330 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO)); 1331 count = ImmGetIMCCLockCount(imcc); 1332 ok(count == 0, "expect 0, returned %d\n", count); 1333 ImmLockIMCC(imcc); 1334 count = ImmGetIMCCLockCount(imcc); 1335 ok(count == 1, "expect 1, returned %d\n", count); 1336 ret = ImmUnlockIMCC(imcc); 1337 ok(ret == FALSE, "expect FALSE, ret %d\n", ret); 1338 count = ImmGetIMCCLockCount(imcc); 1339 ok(count == 0, "expect 0, returned %d\n", count); 1340 ret = ImmUnlockIMCC(imcc); 1341 ok(ret == FALSE, "expect FALSE, ret %d\n", ret); 1342 count = ImmGetIMCCLockCount(imcc); 1343 ok(count == 0, "expect 0, returned %d\n", count); 1344 1345 p = ImmLockIMCC(imcc); 1346 ok(GlobalHandle(p) == imcc, "expect %p, returned %p\n", imcc, GlobalHandle(p)); 1347 1348 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++) 1349 { 1350 ImmLockIMCC(imcc); 1351 count = ImmGetIMCCLockCount(imcc); 1352 g_count = GlobalFlags(imcc) & GMEM_LOCKCOUNT; 1353 ok(count == g_count, "count %d, g_count %d\n", count, g_count); 1354 } 1355 count = ImmGetIMCCLockCount(imcc); 1356 ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %d\n", count); 1357 1358 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++) 1359 GlobalUnlock(imcc); 1360 count = ImmGetIMCCLockCount(imcc); 1361 ok(count == 1, "expect 1, returned %d\n", count); 1362 GlobalUnlock(imcc); 1363 count = ImmGetIMCCLockCount(imcc); 1364 ok(count == 0, "expect 0, returned %d\n", count); 1365 1366 ImmDestroyIMCC(imcc); 1367 } 1368 1369 static void test_ImmDestroyContext(void) 1370 { 1371 HIMC imc; 1372 DWORD ret, count; 1373 INPUTCONTEXT *ic; 1374 1375 imc = ImmCreateContext(); 1376 count = ImmGetIMCLockCount(imc); 1377 ok(count == 0, "expect 0, returned %d\n", count); 1378 ic = ImmLockIMC(imc); 1379 ok(ic != NULL, "ImmLockIMC failed!\n"); 1380 count = ImmGetIMCLockCount(imc); 1381 ok(count == 1, "expect 1, returned %d\n", count); 1382 ret = ImmDestroyContext(imc); 1383 ok(ret == TRUE, "Destroy a locked IMC should success!\n"); 1384 ic = ImmLockIMC(imc); 1385 ok(ic == NULL, "Lock a destroyed IMC should fail!\n"); 1386 ret = ImmUnlockIMC(imc); 1387 ok(ret == FALSE, "Unlock a destroyed IMC should fail!\n"); 1388 count = ImmGetIMCLockCount(imc); 1389 ok(count == 0, "Get lock count of a destroyed IMC should return 0!\n"); 1390 SetLastError(0xdeadbeef); 1391 ret = ImmDestroyContext(imc); 1392 ok(ret == FALSE, "Destroy a destroyed IMC should fail!\n"); 1393 ret = GetLastError(); 1394 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1395 } 1396 1397 static void test_ImmDestroyIMCC(void) 1398 { 1399 HIMCC imcc; 1400 DWORD ret, count, size; 1401 VOID *p; 1402 1403 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO)); 1404 count = ImmGetIMCCLockCount(imcc); 1405 ok(count == 0, "expect 0, returned %d\n", count); 1406 p = ImmLockIMCC(imcc); 1407 ok(p != NULL, "ImmLockIMCC failed!\n"); 1408 count = ImmGetIMCCLockCount(imcc); 1409 ok(count == 1, "expect 1, returned %d\n", count); 1410 size = ImmGetIMCCSize(imcc); 1411 ok(size == sizeof(CANDIDATEINFO), "returned %d\n", size); 1412 p = ImmDestroyIMCC(imcc); 1413 ok(p == NULL, "Destroy a locked IMCC should success!\n"); 1414 p = ImmLockIMCC(imcc); 1415 ok(p == NULL, "Lock a destroyed IMCC should fail!\n"); 1416 ret = ImmUnlockIMCC(imcc); 1417 ok(ret == FALSE, "Unlock a destroyed IMCC should return FALSE!\n"); 1418 count = ImmGetIMCCLockCount(imcc); 1419 ok(count == 0, "Get lock count of a destroyed IMCC should return 0!\n"); 1420 size = ImmGetIMCCSize(imcc); 1421 ok(size == 0, "Get size of a destroyed IMCC should return 0!\n"); 1422 SetLastError(0xdeadbeef); 1423 p = ImmDestroyIMCC(imcc); 1424 ok(p != NULL, "returned NULL\n"); 1425 ret = GetLastError(); 1426 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1427 } 1428 1429 static void test_ImmMessages(void) 1430 { 1431 CANDIDATEFORM cf; 1432 imm_msgs *msg; 1433 HWND defwnd; 1434 HIMC imc; 1435 UINT idx = 0; 1436 1437 LPINPUTCONTEXT lpIMC; 1438 LPTRANSMSG lpTransMsg; 1439 1440 HWND hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test", 1441 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1442 240, 120, NULL, NULL, GetModuleHandleA(NULL), NULL); 1443 1444 ShowWindow(hwnd, SW_SHOWNORMAL); 1445 defwnd = ImmGetDefaultIMEWnd(hwnd); 1446 imc = ImmGetContext(hwnd); 1447 1448 ImmSetOpenStatus(imc, TRUE); 1449 msg_spy_flush_msgs(); 1450 SendMessageA(defwnd, WM_IME_CONTROL, IMC_GETCANDIDATEPOS, (LPARAM)&cf ); 1451 do 1452 { 1453 msg = msg_spy_find_next_msg(WM_IME_CONTROL,&idx); 1454 if (msg) ok(!msg->post, "Message should not be posted\n"); 1455 } while (msg); 1456 msg_spy_flush_msgs(); 1457 1458 lpIMC = ImmLockIMC(imc); 1459 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); 1460 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); 1461 lpTransMsg += lpIMC->dwNumMsgBuf; 1462 lpTransMsg->message = WM_IME_STARTCOMPOSITION; 1463 lpTransMsg->wParam = 0; 1464 lpTransMsg->lParam = 0; 1465 ImmUnlockIMCC(lpIMC->hMsgBuf); 1466 lpIMC->dwNumMsgBuf++; 1467 ImmUnlockIMC(imc); 1468 ImmGenerateMessage(imc); 1469 idx = 0; 1470 do 1471 { 1472 msg = msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION, &idx); 1473 if (msg) ok(!msg->post, "Message should not be posted\n"); 1474 } while (msg); 1475 msg_spy_flush_msgs(); 1476 1477 lpIMC = ImmLockIMC(imc); 1478 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); 1479 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); 1480 lpTransMsg += lpIMC->dwNumMsgBuf; 1481 lpTransMsg->message = WM_IME_COMPOSITION; 1482 lpTransMsg->wParam = 0; 1483 lpTransMsg->lParam = 0; 1484 ImmUnlockIMCC(lpIMC->hMsgBuf); 1485 lpIMC->dwNumMsgBuf++; 1486 ImmUnlockIMC(imc); 1487 ImmGenerateMessage(imc); 1488 idx = 0; 1489 do 1490 { 1491 msg = msg_spy_find_next_msg(WM_IME_COMPOSITION, &idx); 1492 if (msg) ok(!msg->post, "Message should not be posted\n"); 1493 } while (msg); 1494 msg_spy_flush_msgs(); 1495 1496 lpIMC = ImmLockIMC(imc); 1497 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); 1498 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); 1499 lpTransMsg += lpIMC->dwNumMsgBuf; 1500 lpTransMsg->message = WM_IME_ENDCOMPOSITION; 1501 lpTransMsg->wParam = 0; 1502 lpTransMsg->lParam = 0; 1503 ImmUnlockIMCC(lpIMC->hMsgBuf); 1504 lpIMC->dwNumMsgBuf++; 1505 ImmUnlockIMC(imc); 1506 ImmGenerateMessage(imc); 1507 idx = 0; 1508 do 1509 { 1510 msg = msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION, &idx); 1511 if (msg) ok(!msg->post, "Message should not be posted\n"); 1512 } while (msg); 1513 msg_spy_flush_msgs(); 1514 1515 ImmSetOpenStatus(imc, FALSE); 1516 ImmReleaseContext(hwnd, imc); 1517 DestroyWindow(hwnd); 1518 } 1519 1520 static LRESULT CALLBACK processkey_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam, 1521 LPARAM lParam ) 1522 { 1523 return DefWindowProcW(hWnd, msg, wParam, lParam); 1524 } 1525 1526 static void test_ime_processkey(void) 1527 { 1528 WCHAR classNameW[] = {'P','r','o','c','e','s','s', 'K','e','y','T','e','s','t','C','l','a','s','s',0}; 1529 WCHAR windowNameW[] = {'P','r','o','c','e','s','s', 'K','e','y',0}; 1530 1531 MSG msg; 1532 WNDCLASSW wclass; 1533 HANDLE hInstance = GetModuleHandleW(NULL); 1534 TEST_INPUT inputs[2]; 1535 HIMC imc; 1536 INT rc; 1537 HWND hWndTest; 1538 1539 wclass.lpszClassName = classNameW; 1540 wclass.style = CS_HREDRAW | CS_VREDRAW; 1541 wclass.lpfnWndProc = processkey_wnd_proc; 1542 wclass.hInstance = hInstance; 1543 wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); 1544 wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW); 1545 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 1546 wclass.lpszMenuName = 0; 1547 wclass.cbClsExtra = 0; 1548 wclass.cbWndExtra = 0; 1549 if(!RegisterClassW(&wclass)){ 1550 win_skip("Failed to register window.\n"); 1551 return; 1552 } 1553 1554 /* create the test window that will receive the keystrokes */ 1555 hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW, 1556 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100, 1557 NULL, NULL, hInstance, NULL); 1558 1559 ShowWindow(hWndTest, SW_SHOW); 1560 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); 1561 SetForegroundWindow(hWndTest); 1562 UpdateWindow(hWndTest); 1563 1564 imc = ImmGetContext(hWndTest); 1565 if (!imc) 1566 { 1567 win_skip("IME not supported\n"); 1568 DestroyWindow(hWndTest); 1569 return; 1570 } 1571 1572 rc = ImmSetOpenStatus(imc, TRUE); 1573 if (rc != TRUE) 1574 { 1575 win_skip("Unable to open IME\n"); 1576 ImmReleaseContext(hWndTest, imc); 1577 DestroyWindow(hWndTest); 1578 return; 1579 } 1580 1581 /* flush pending messages */ 1582 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); 1583 1584 SetFocus(hWndTest); 1585 1586 /* init input data that never changes */ 1587 inputs[1].type = inputs[0].type = INPUT_KEYBOARD; 1588 inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0; 1589 inputs[1].u.ki.time = inputs[0].u.ki.time = 0; 1590 1591 /* Pressing a key */ 1592 inputs[0].u.ki.wVk = 0x41; 1593 inputs[0].u.ki.wScan = 0x1e; 1594 inputs[0].u.ki.dwFlags = 0x0; 1595 1596 pSendInput(1, (INPUT*)inputs, sizeof(INPUT)); 1597 1598 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) { 1599 if(msg.message != WM_KEYDOWN) 1600 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1601 else 1602 { 1603 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n"); 1604 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1605 if(msg.wParam == VK_PROCESSKEY) 1606 trace("ProcessKey was correctly found\n"); 1607 } 1608 TranslateMessage(&msg); 1609 DispatchMessageW(&msg); 1610 } 1611 1612 inputs[0].u.ki.wVk = 0x41; 1613 inputs[0].u.ki.wScan = 0x1e; 1614 inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP; 1615 1616 pSendInput(1, (INPUT*)inputs, sizeof(INPUT)); 1617 1618 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) { 1619 if(msg.message != WM_KEYUP) 1620 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1621 else 1622 { 1623 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n"); 1624 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE); 1625 ok(msg.wParam != VK_PROCESSKEY,"ProcessKey should still not be Found\n"); 1626 } 1627 TranslateMessage(&msg); 1628 DispatchMessageW(&msg); 1629 } 1630 1631 ImmReleaseContext(hWndTest, imc); 1632 ImmSetOpenStatus(imc, FALSE); 1633 DestroyWindow(hWndTest); 1634 } 1635 1636 static void test_InvalidIMC(void) 1637 { 1638 HIMC imc_destroy; 1639 HIMC imc_null = 0x00000000; 1640 HIMC imc_bad = (HIMC)0xdeadcafe; 1641 1642 HIMC imc1, imc2, oldimc; 1643 DWORD ret; 1644 DWORD count; 1645 CHAR buffer[1000]; 1646 INPUTCONTEXT *ic; 1647 LOGFONTA lf; 1648 1649 memset(&lf, 0, sizeof(lf)); 1650 1651 imc_destroy = ImmCreateContext(); 1652 ret = ImmDestroyContext(imc_destroy); 1653 ok(ret == TRUE, "Destroy an IMC should success!\n"); 1654 1655 /* Test associating destroyed imc */ 1656 imc1 = ImmGetContext(hwnd); 1657 SetLastError(0xdeadbeef); 1658 oldimc = ImmAssociateContext(hwnd, imc_destroy); 1659 ok(!oldimc, "Associating to a destroyed imc should fail!\n"); 1660 ret = GetLastError(); 1661 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1662 imc2 = ImmGetContext(hwnd); 1663 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2); 1664 1665 /* Test associating NULL imc, which is different from an invalid imc */ 1666 oldimc = ImmAssociateContext(hwnd, imc_null); 1667 ok(oldimc != NULL, "Associating to NULL imc should success!\n"); 1668 imc2 = ImmGetContext(hwnd); 1669 ok(!imc2, "expect NULL, returned %p\n", imc2); 1670 oldimc = ImmAssociateContext(hwnd, imc1); 1671 ok(!oldimc, "expect NULL, returned %p\n", oldimc); 1672 imc2 = ImmGetContext(hwnd); 1673 ok(imc2 == imc1, "imc should not changed! imc2 %p, imc1 %p\n", imc2, imc1); 1674 1675 /* Test associating invalid imc */ 1676 imc1 = ImmGetContext(hwnd); 1677 SetLastError(0xdeadbeef); 1678 oldimc = ImmAssociateContext(hwnd, imc_bad); 1679 ok(!oldimc, "Associating to a destroyed imc should fail!\n"); 1680 ret = GetLastError(); 1681 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1682 imc2 = ImmGetContext(hwnd); 1683 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2); 1684 1685 1686 /* Test ImmGetCandidateListA */ 1687 SetLastError(0xdeadbeef); 1688 ret = ImmGetCandidateListA(imc_bad, 0, NULL, 0); 1689 ok(ret == 0, "Bad IME should return 0\n"); 1690 ret = GetLastError(); 1691 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1692 SetLastError(0xdeadbeef); 1693 ret = ImmGetCandidateListA(imc_null, 0, NULL, 0); 1694 ok(ret == 0, "NULL IME should return 0\n"); 1695 ret = GetLastError(); 1696 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1697 SetLastError(0xdeadbeef); 1698 ret = ImmGetCandidateListA(imc_destroy, 0, NULL, 0); 1699 ok(ret == 0, "Destroyed IME should return 0\n"); 1700 ret = GetLastError(); 1701 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1702 1703 /* Test ImmGetCandidateListCountA*/ 1704 SetLastError(0xdeadbeef); 1705 ret = ImmGetCandidateListCountA(imc_bad,&count); 1706 ok(ret == 0, "Bad IME should return 0\n"); 1707 ret = GetLastError(); 1708 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1709 SetLastError(0xdeadbeef); 1710 ret = ImmGetCandidateListCountA(imc_null,&count); 1711 ok(ret == 0, "NULL IME should return 0\n"); 1712 ret = GetLastError(); 1713 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1714 SetLastError(0xdeadbeef); 1715 ret = ImmGetCandidateListCountA(imc_destroy,&count); 1716 ok(ret == 0, "Destroyed IME should return 0\n"); 1717 ret = GetLastError(); 1718 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1719 1720 /* Test ImmGetCandidateWindow */ 1721 SetLastError(0xdeadbeef); 1722 ret = ImmGetCandidateWindow(imc_bad, 0, (LPCANDIDATEFORM)buffer); 1723 ok(ret == 0, "Bad IME should return 0\n"); 1724 ret = GetLastError(); 1725 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1726 SetLastError(0xdeadbeef); 1727 ret = ImmGetCandidateWindow(imc_null, 0, (LPCANDIDATEFORM)buffer); 1728 ok(ret == 0, "NULL IME should return 0\n"); 1729 ret = GetLastError(); 1730 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1731 SetLastError(0xdeadbeef); 1732 ret = ImmGetCandidateWindow(imc_destroy, 0, (LPCANDIDATEFORM)buffer); 1733 ok(ret == 0, "Destroyed IME should return 0\n"); 1734 ret = GetLastError(); 1735 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1736 1737 /* Test ImmGetCompositionFontA */ 1738 SetLastError(0xdeadbeef); 1739 ret = ImmGetCompositionFontA(imc_bad, (LPLOGFONTA)buffer); 1740 ok(ret == 0, "Bad IME should return 0\n"); 1741 ret = GetLastError(); 1742 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1743 SetLastError(0xdeadbeef); 1744 ret = ImmGetCompositionFontA(imc_null, (LPLOGFONTA)buffer); 1745 ok(ret == 0, "NULL IME should return 0\n"); 1746 ret = GetLastError(); 1747 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1748 SetLastError(0xdeadbeef); 1749 ret = ImmGetCompositionFontA(imc_destroy, (LPLOGFONTA)buffer); 1750 ok(ret == 0, "Destroyed IME should return 0\n"); 1751 ret = GetLastError(); 1752 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1753 1754 /* Test ImmGetCompositionWindow */ 1755 SetLastError(0xdeadbeef); 1756 ret = ImmGetCompositionWindow(imc_bad, (LPCOMPOSITIONFORM)buffer); 1757 ok(ret == 0, "Bad IME should return 0\n"); 1758 ret = GetLastError(); 1759 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1760 SetLastError(0xdeadbeef); 1761 ret = ImmGetCompositionWindow(imc_null, (LPCOMPOSITIONFORM)buffer); 1762 ok(ret == 0, "NULL IME should return 0\n"); 1763 ret = GetLastError(); 1764 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1765 SetLastError(0xdeadbeef); 1766 ret = ImmGetCompositionWindow(imc_destroy, (LPCOMPOSITIONFORM)buffer); 1767 ok(ret == 0, "Destroyed IME should return 0\n"); 1768 ret = GetLastError(); 1769 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1770 1771 /* Test ImmGetCompositionStringA */ 1772 SetLastError(0xdeadbeef); 1773 ret = ImmGetCompositionStringA(imc_bad, GCS_COMPSTR, NULL, 0); 1774 ok(ret == 0, "Bad IME should return 0\n"); 1775 ret = GetLastError(); 1776 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1777 SetLastError(0xdeadbeef); 1778 ret = ImmGetCompositionStringA(imc_null, GCS_COMPSTR, NULL, 0); 1779 ok(ret == 0, "NULL IME should return 0\n"); 1780 ret = GetLastError(); 1781 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1782 SetLastError(0xdeadbeef); 1783 ret = ImmGetCompositionStringA(imc_destroy, GCS_COMPSTR, NULL, 0); 1784 ok(ret == 0, "Destroyed IME should return 0\n"); 1785 ret = GetLastError(); 1786 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1787 1788 /* Test ImmSetOpenStatus */ 1789 SetLastError(0xdeadbeef); 1790 ret = ImmSetOpenStatus(imc_bad, 1); 1791 ok(ret == 0, "Bad IME should return 0\n"); 1792 ret = GetLastError(); 1793 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1794 SetLastError(0xdeadbeef); 1795 ret = ImmSetOpenStatus(imc_null, 1); 1796 ok(ret == 0, "NULL IME should return 0\n"); 1797 ret = GetLastError(); 1798 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1799 SetLastError(0xdeadbeef); 1800 ret = ImmSetOpenStatus(imc_destroy, 1); 1801 ok(ret == 0, "Destroyed IME should return 0\n"); 1802 ret = GetLastError(); 1803 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1804 1805 /* Test ImmGetOpenStatus */ 1806 SetLastError(0xdeadbeef); 1807 ret = ImmGetOpenStatus(imc_bad); 1808 ok(ret == 0, "Bad IME should return 0\n"); 1809 ret = GetLastError(); 1810 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1811 SetLastError(0xdeadbeef); 1812 ret = ImmGetOpenStatus(imc_null); 1813 ok(ret == 0, "NULL IME should return 0\n"); 1814 ret = GetLastError(); 1815 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1816 SetLastError(0xdeadbeef); 1817 ret = ImmGetOpenStatus(imc_destroy); 1818 ok(ret == 0, "Destroyed IME should return 0\n"); 1819 ret = GetLastError(); 1820 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1821 1822 /* Test ImmGetStatusWindowPos */ 1823 SetLastError(0xdeadbeef); 1824 ret = ImmGetStatusWindowPos(imc_bad, NULL); 1825 ok(ret == 0, "Bad IME should return 0\n"); 1826 ret = GetLastError(); 1827 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1828 SetLastError(0xdeadbeef); 1829 ret = ImmGetStatusWindowPos(imc_null, NULL); 1830 ok(ret == 0, "NULL IME should return 0\n"); 1831 ret = GetLastError(); 1832 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1833 SetLastError(0xdeadbeef); 1834 ret = ImmGetStatusWindowPos(imc_destroy, NULL); 1835 ok(ret == 0, "Destroyed IME should return 0\n"); 1836 ret = GetLastError(); 1837 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1838 1839 /* Test ImmRequestMessageA */ 1840 SetLastError(0xdeadbeef); 1841 ret = ImmRequestMessageA(imc_bad, WM_CHAR, 0); 1842 ok(ret == 0, "Bad IME should return 0\n"); 1843 ret = GetLastError(); 1844 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1845 SetLastError(0xdeadbeef); 1846 ret = ImmRequestMessageA(imc_null, WM_CHAR, 0); 1847 ok(ret == 0, "NULL IME should return 0\n"); 1848 ret = GetLastError(); 1849 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1850 SetLastError(0xdeadbeef); 1851 ret = ImmRequestMessageA(imc_destroy, WM_CHAR, 0); 1852 ok(ret == 0, "Destroyed IME should return 0\n"); 1853 ret = GetLastError(); 1854 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1855 1856 /* Test ImmSetCompositionFontA */ 1857 SetLastError(0xdeadbeef); 1858 ret = ImmSetCompositionFontA(imc_bad, &lf); 1859 ok(ret == 0, "Bad IME should return 0\n"); 1860 ret = GetLastError(); 1861 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1862 SetLastError(0xdeadbeef); 1863 ret = ImmSetCompositionFontA(imc_null, &lf); 1864 ok(ret == 0, "NULL IME should return 0\n"); 1865 ret = GetLastError(); 1866 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1867 SetLastError(0xdeadbeef); 1868 ret = ImmSetCompositionFontA(imc_destroy, &lf); 1869 ok(ret == 0, "Destroyed IME should return 0\n"); 1870 ret = GetLastError(); 1871 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1872 1873 /* Test ImmSetCompositionWindow */ 1874 SetLastError(0xdeadbeef); 1875 ret = ImmSetCompositionWindow(imc_bad, NULL); 1876 ok(ret == 0, "Bad IME should return 0\n"); 1877 ret = GetLastError(); 1878 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1879 SetLastError(0xdeadbeef); 1880 ret = ImmSetCompositionWindow(imc_null, NULL); 1881 ok(ret == 0, "NULL IME should return 0\n"); 1882 ret = GetLastError(); 1883 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1884 SetLastError(0xdeadbeef); 1885 ret = ImmSetCompositionWindow(imc_destroy, NULL); 1886 ok(ret == 0, "Destroyed IME should return 0\n"); 1887 ret = GetLastError(); 1888 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1889 1890 /* Test ImmSetConversionStatus */ 1891 SetLastError(0xdeadbeef); 1892 ret = ImmSetConversionStatus(imc_bad, 0, 0); 1893 ok(ret == 0, "Bad IME should return 0\n"); 1894 ret = GetLastError(); 1895 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1896 SetLastError(0xdeadbeef); 1897 ret = ImmSetConversionStatus(imc_null, 0, 0); 1898 ok(ret == 0, "NULL IME should return 0\n"); 1899 ret = GetLastError(); 1900 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1901 SetLastError(0xdeadbeef); 1902 ret = ImmSetConversionStatus(imc_destroy, 0, 0); 1903 ok(ret == 0, "Destroyed IME should return 0\n"); 1904 ret = GetLastError(); 1905 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1906 1907 /* Test ImmSetStatusWindowPos */ 1908 SetLastError(0xdeadbeef); 1909 ret = ImmSetStatusWindowPos(imc_bad, 0); 1910 ok(ret == 0, "Bad IME should return 0\n"); 1911 ret = GetLastError(); 1912 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1913 SetLastError(0xdeadbeef); 1914 ret = ImmSetStatusWindowPos(imc_null, 0); 1915 ok(ret == 0, "NULL IME should return 0\n"); 1916 ret = GetLastError(); 1917 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1918 SetLastError(0xdeadbeef); 1919 ret = ImmSetStatusWindowPos(imc_destroy, 0); 1920 ok(ret == 0, "Destroyed IME should return 0\n"); 1921 ret = GetLastError(); 1922 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1923 1924 /* Test ImmGetImeMenuItemsA */ 1925 SetLastError(0xdeadbeef); 1926 ret = ImmGetImeMenuItemsA(imc_bad, 0, 0, NULL, NULL, 0); 1927 ok(ret == 0, "Bad IME should return 0\n"); 1928 ret = GetLastError(); 1929 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1930 SetLastError(0xdeadbeef); 1931 ret = ImmGetImeMenuItemsA(imc_null, 0, 0, NULL, NULL, 0); 1932 ok(ret == 0, "NULL IME should return 0\n"); 1933 ret = GetLastError(); 1934 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1935 SetLastError(0xdeadbeef); 1936 ret = ImmGetImeMenuItemsA(imc_destroy, 0, 0, NULL, NULL, 0); 1937 ok(ret == 0, "Destroyed IME should return 0\n"); 1938 ret = GetLastError(); 1939 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1940 1941 /* Test ImmLockIMC */ 1942 SetLastError(0xdeadbeef); 1943 ic = ImmLockIMC(imc_bad); 1944 ok(ic == 0, "Bad IME should return 0\n"); 1945 ret = GetLastError(); 1946 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1947 SetLastError(0xdeadbeef); 1948 ic = ImmLockIMC(imc_null); 1949 ok(ic == 0, "NULL IME should return 0\n"); 1950 ret = GetLastError(); 1951 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1952 SetLastError(0xdeadbeef); 1953 ic = ImmLockIMC(imc_destroy); 1954 ok(ic == 0, "Destroyed IME should return 0\n"); 1955 ret = GetLastError(); 1956 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1957 1958 /* Test ImmUnlockIMC */ 1959 SetLastError(0xdeadbeef); 1960 ret = ImmUnlockIMC(imc_bad); 1961 ok(ret == 0, "Bad IME should return 0\n"); 1962 ret = GetLastError(); 1963 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1964 SetLastError(0xdeadbeef); 1965 ret = ImmUnlockIMC(imc_null); 1966 ok(ret == 0, "NULL IME should return 0\n"); 1967 ret = GetLastError(); 1968 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret); 1969 SetLastError(0xdeadbeef); 1970 ret = ImmUnlockIMC(imc_destroy); 1971 ok(ret == 0, "Destroyed IME should return 0\n"); 1972 ret = GetLastError(); 1973 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1974 1975 /* Test ImmGenerateMessage */ 1976 SetLastError(0xdeadbeef); 1977 ret = ImmGenerateMessage(imc_bad); 1978 ok(ret == 0, "Bad IME should return 0\n"); 1979 ret = GetLastError(); 1980 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1981 SetLastError(0xdeadbeef); 1982 ret = ImmGenerateMessage(imc_null); 1983 ok(ret == 0, "NULL IME should return 0\n"); 1984 ret = GetLastError(); 1985 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1986 SetLastError(0xdeadbeef); 1987 ret = ImmGenerateMessage(imc_destroy); 1988 ok(ret == 0, "Destroyed IME should return 0\n"); 1989 ret = GetLastError(); 1990 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); 1991 } 1992 1993 START_TEST(imm32) { 1994 if (init()) 1995 { 1996 test_ImmNotifyIME(); 1997 test_ImmGetCompositionString(); 1998 test_ImmSetCompositionString(); 1999 test_ImmIME(); 2000 test_ImmAssociateContextEx(); 2001 test_ImmThreads(); 2002 test_ImmIsUIMessage(); 2003 test_ImmGetContext(); 2004 test_ImmGetDescription(); 2005 test_ImmDefaultHwnd(); 2006 test_default_ime_window_creation(); 2007 test_ImmGetIMCLockCount(); 2008 test_ImmGetIMCCLockCount(); 2009 test_ImmDestroyContext(); 2010 test_ImmDestroyIMCC(); 2011 test_InvalidIMC(); 2012 msg_spy_cleanup(); 2013 /* Reinitialize the hooks to capture all windows */ 2014 msg_spy_init(NULL); 2015 test_ImmMessages(); 2016 msg_spy_cleanup(); 2017 if (pSendInput) 2018 test_ime_processkey(); 2019 else win_skip("SendInput is not available\n"); 2020 } 2021 cleanup(); 2022 } 2023