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