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