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