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