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