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