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