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