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