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