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 }
1876