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