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