imm32: Implement ImmDisableIME.
[wine.git] / dlls / imm32 / tests / imm32.c
blobf0f32a720389d50e259aafd3517cd2fe15161381
1 /*
2 * Unit tests for imm32
4 * Copyright (c) 2008 Michael Jung
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.
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.
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
21 #include <stdio.h>
23 #include "wine/test.h"
24 #include "winuser.h"
25 #include "wingdi.h"
26 #include "imm.h"
27 #include "ddk/imm.h"
29 #define NUMELEMS(array) (sizeof((array))/sizeof((array)[0]))
31 static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD);
32 static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM);
33 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
36 * msgspy - record and analyse message traces sent to a certain window
38 typedef struct _msgs {
39 CWPSTRUCT msg;
40 BOOL post;
41 } imm_msgs;
43 static struct _msg_spy {
44 HWND hwnd;
45 HHOOK get_msg_hook;
46 HHOOK call_wnd_proc_hook;
47 imm_msgs msgs[64];
48 unsigned int i_msg;
49 } msg_spy;
51 typedef struct
53 DWORD type;
54 union
56 MOUSEINPUT mi;
57 KEYBDINPUT ki;
58 HARDWAREINPUT hi;
59 } u;
60 } TEST_INPUT;
62 typedef struct _tagTRANSMSG {
63 UINT message;
64 WPARAM wParam;
65 LPARAM lParam;
66 } TRANSMSG, *LPTRANSMSG;
68 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
70 static LRESULT CALLBACK get_msg_filter(int nCode, WPARAM wParam, LPARAM lParam)
72 if (HC_ACTION == nCode) {
73 MSG *msg = (MSG*)lParam;
75 if ((msg->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL) &&
76 (msg_spy.i_msg < NUMELEMS(msg_spy.msgs)))
78 msg_spy.msgs[msg_spy.i_msg].msg.hwnd = msg->hwnd;
79 msg_spy.msgs[msg_spy.i_msg].msg.message = msg->message;
80 msg_spy.msgs[msg_spy.i_msg].msg.wParam = msg->wParam;
81 msg_spy.msgs[msg_spy.i_msg].msg.lParam = msg->lParam;
82 msg_spy.msgs[msg_spy.i_msg].post = TRUE;
83 msg_spy.i_msg++;
87 return CallNextHookEx(msg_spy.get_msg_hook, nCode, wParam, lParam);
90 static LRESULT CALLBACK call_wnd_proc_filter(int nCode, WPARAM wParam,
91 LPARAM lParam)
93 if (HC_ACTION == nCode) {
94 CWPSTRUCT *cwp = (CWPSTRUCT*)lParam;
96 if (((cwp->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL)) &&
97 (msg_spy.i_msg < NUMELEMS(msg_spy.msgs)))
99 memcpy(&msg_spy.msgs[msg_spy.i_msg].msg, cwp, sizeof(msg_spy.msgs[0].msg));
100 msg_spy.msgs[msg_spy.i_msg].post = FALSE;
101 msg_spy.i_msg++;
105 return CallNextHookEx(msg_spy.call_wnd_proc_hook, nCode, wParam, lParam);
108 static void msg_spy_pump_msg_queue(void) {
109 MSG msg;
111 while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
112 TranslateMessage(&msg);
113 DispatchMessageW(&msg);
116 return;
119 static void msg_spy_flush_msgs(void) {
120 msg_spy_pump_msg_queue();
121 msg_spy.i_msg = 0;
124 static imm_msgs* msg_spy_find_next_msg(UINT message, UINT *start) {
125 UINT i;
127 msg_spy_pump_msg_queue();
129 if (msg_spy.i_msg >= NUMELEMS(msg_spy.msgs))
130 fprintf(stdout, "%s:%d: msg_spy: message buffer overflow!\n",
131 __FILE__, __LINE__);
133 for (i = *start; i < msg_spy.i_msg; i++)
134 if (msg_spy.msgs[i].msg.message == message)
136 *start = i+1;
137 return &msg_spy.msgs[i];
140 return NULL;
143 static imm_msgs* msg_spy_find_msg(UINT message) {
144 UINT i = 0;
146 return msg_spy_find_next_msg(message, &i);
149 static void msg_spy_init(HWND hwnd) {
150 msg_spy.hwnd = hwnd;
151 msg_spy.get_msg_hook =
152 SetWindowsHookExW(WH_GETMESSAGE, get_msg_filter, GetModuleHandleW(NULL),
153 GetCurrentThreadId());
154 msg_spy.call_wnd_proc_hook =
155 SetWindowsHookExW(WH_CALLWNDPROC, call_wnd_proc_filter,
156 GetModuleHandleW(NULL), GetCurrentThreadId());
157 msg_spy.i_msg = 0;
159 msg_spy_flush_msgs();
162 static void msg_spy_cleanup(void) {
163 if (msg_spy.get_msg_hook)
164 UnhookWindowsHookEx(msg_spy.get_msg_hook);
165 if (msg_spy.call_wnd_proc_hook)
166 UnhookWindowsHookEx(msg_spy.call_wnd_proc_hook);
167 memset(&msg_spy, 0, sizeof(msg_spy));
171 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the
172 * messages being sent to this window in response.
174 static const char wndcls[] = "winetest_imm32_wndcls";
175 static enum { PHASE_UNKNOWN, FIRST_WINDOW, SECOND_WINDOW,
176 CREATE_CANCEL, NCCREATE_CANCEL, IME_DISABLED } test_phase;
177 static HWND hwnd;
179 static HWND get_ime_window(void);
181 static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
183 HWND default_ime_wnd;
184 switch (msg)
186 case WM_IME_SETCONTEXT:
187 return TRUE;
188 case WM_NCCREATE:
189 default_ime_wnd = get_ime_window();
190 switch(test_phase) {
191 case FIRST_WINDOW:
192 case IME_DISABLED:
193 ok(!default_ime_wnd, "expected no IME windows\n");
194 break;
195 case SECOND_WINDOW:
196 ok(default_ime_wnd != NULL, "expected IME window existence\n");
197 break;
198 default:
199 break; /* do nothing */
201 if (test_phase == NCCREATE_CANCEL)
202 return FALSE;
203 return TRUE;
204 case WM_NCCALCSIZE:
205 default_ime_wnd = get_ime_window();
206 switch(test_phase) {
207 case FIRST_WINDOW:
208 case SECOND_WINDOW:
209 case CREATE_CANCEL:
210 todo_wine_if(test_phase == FIRST_WINDOW || test_phase == CREATE_CANCEL)
211 ok(default_ime_wnd != NULL, "expected IME window existence\n");
212 break;
213 case IME_DISABLED:
214 ok(!default_ime_wnd, "expected no IME windows\n");
215 break;
216 default:
217 break; /* do nothing */
219 break;
220 case WM_CREATE:
221 default_ime_wnd = get_ime_window();
222 switch(test_phase) {
223 case FIRST_WINDOW:
224 case SECOND_WINDOW:
225 case CREATE_CANCEL:
226 todo_wine_if(test_phase == FIRST_WINDOW || test_phase == 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 */
235 if (test_phase == CREATE_CANCEL)
236 return -1;
237 return TRUE;
240 return DefWindowProcA(hWnd,msg,wParam,lParam);
243 static BOOL init(void) {
244 WNDCLASSEXA wc;
245 HIMC imc;
246 HMODULE hmod,huser;
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");
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);
267 if (!RegisterClassExA(&wc))
268 return FALSE;
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;
276 imc = ImmGetContext(hwnd);
277 if (!imc)
279 win_skip("IME support not implemented\n");
280 return FALSE;
282 ImmReleaseContext(hwnd, imc);
284 ShowWindow(hwnd, SW_SHOWNORMAL);
285 UpdateWindow(hwnd);
287 msg_spy_init(hwnd);
289 return TRUE;
292 static void cleanup(void) {
293 msg_spy_cleanup();
294 if (hwnd)
295 DestroyWindow(hwnd);
296 UnregisterClassA(wndcls, GetModuleHandleW(NULL));
299 static void test_ImmNotifyIME(void) {
300 static const char string[] = "wine";
301 char resstr[16] = "";
302 HIMC imc;
303 BOOL ret;
305 imc = ImmGetContext(hwnd);
306 msg_spy_flush_msgs();
308 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
309 ok(broken(!ret) ||
310 ret, /* Vista+ */
311 "Canceling an empty composition string should succeed.\n");
312 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post "
313 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
314 "the composition string being canceled is empty.\n");
316 ImmSetCompositionStringA(imc, SCS_SETSTR, string, sizeof(string), NULL, 0);
317 msg_spy_flush_msgs();
319 ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
320 msg_spy_flush_msgs();
322 /* behavior differs between win9x and NT */
323 ret = ImmGetCompositionStringA(imc, GCS_COMPSTR, resstr, sizeof(resstr));
324 ok(!ret, "After being cancelled the composition string is empty.\n");
326 msg_spy_flush_msgs();
328 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
329 ok(broken(!ret) ||
330 ret, /* Vista+ */
331 "Canceling an empty composition string should succeed.\n");
332 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post "
333 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
334 "the composition string being canceled is empty.\n");
336 msg_spy_flush_msgs();
337 ImmReleaseContext(hwnd, imc);
339 imc = ImmCreateContext();
340 ImmDestroyContext(imc);
342 SetLastError(0xdeadbeef);
343 ret = ImmNotifyIME((HIMC)0xdeadcafe, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
344 ok (ret == 0, "Bad IME should return 0\n");
345 ret = GetLastError();
346 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
347 SetLastError(0xdeadbeef);
348 ret = ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
349 ok (ret == 0, "NULL IME should return 0\n");
350 ret = GetLastError();
351 ok(ret == ERROR_SUCCESS, "wrong last error %08x!\n", ret);
352 SetLastError(0xdeadbeef);
353 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
354 ok (ret == 0, "Destroyed IME should return 0\n");
355 ret = GetLastError();
356 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
360 static void test_ImmGetCompositionString(void)
362 HIMC imc;
363 static const WCHAR string[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
364 char cstring[20];
365 WCHAR wstring[20];
366 DWORD len;
367 DWORD alen,wlen;
369 imc = ImmGetContext(hwnd);
370 ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL,0);
371 alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
372 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
373 /* windows machines without any IME installed just return 0 above */
374 if( alen && wlen)
376 len = ImmGetCompositionStringW(imc, GCS_COMPATTR, NULL, 0);
377 ok(len*sizeof(WCHAR)==wlen,"GCS_COMPATTR(W) not returning correct count\n");
378 len = ImmGetCompositionStringA(imc, GCS_COMPATTR, NULL, 0);
379 ok(len==alen,"GCS_COMPATTR(A) not returning correct count\n");
381 ImmReleaseContext(hwnd, imc);
384 static void test_ImmSetCompositionString(void)
386 HIMC imc;
387 BOOL ret;
389 SetLastError(0xdeadbeef);
390 imc = ImmGetContext(hwnd);
391 ok(imc != 0, "ImmGetContext() failed. Last error: %u\n", GetLastError());
392 if (!imc)
393 return;
395 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 0, NULL, 0);
396 ok(broken(!ret) ||
397 ret, /* Vista+ */
398 "ImmSetCompositionStringW() failed.\n");
400 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR,
401 NULL, 0, NULL, 0);
402 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
404 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGECLAUSE,
405 NULL, 0, NULL, 0);
406 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
408 ret = ImmSetCompositionStringW(imc, SCS_CHANGEATTR | SCS_CHANGECLAUSE,
409 NULL, 0, NULL, 0);
410 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
412 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR | SCS_CHANGECLAUSE,
413 NULL, 0, NULL, 0);
414 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
416 ImmReleaseContext(hwnd, imc);
419 static void test_ImmIME(void)
421 HIMC imc;
423 imc = ImmGetContext(hwnd);
424 if (imc)
426 BOOL rc;
427 rc = ImmConfigureIMEA(imc, NULL, IME_CONFIG_REGISTERWORD, NULL);
428 ok (rc == 0, "ImmConfigureIMEA did not fail\n");
429 rc = ImmConfigureIMEW(imc, NULL, IME_CONFIG_REGISTERWORD, NULL);
430 ok (rc == 0, "ImmConfigureIMEW did not fail\n");
432 ImmReleaseContext(hwnd,imc);
435 static void test_ImmAssociateContextEx(void)
437 HIMC imc;
438 BOOL rc;
440 if (!pImmAssociateContextEx) return;
442 imc = ImmGetContext(hwnd);
443 if (imc)
445 HIMC retimc, newimc;
447 newimc = ImmCreateContext();
448 ok(newimc != imc, "handles should not be the same\n");
449 rc = pImmAssociateContextEx(NULL, NULL, 0);
450 ok(!rc, "ImmAssociateContextEx succeeded\n");
451 rc = pImmAssociateContextEx(hwnd, NULL, 0);
452 ok(rc, "ImmAssociateContextEx failed\n");
453 rc = pImmAssociateContextEx(NULL, imc, 0);
454 ok(!rc, "ImmAssociateContextEx succeeded\n");
456 rc = pImmAssociateContextEx(hwnd, imc, 0);
457 ok(rc, "ImmAssociateContextEx failed\n");
458 retimc = ImmGetContext(hwnd);
459 ok(retimc == imc, "handles should be the same\n");
460 ImmReleaseContext(hwnd,retimc);
462 rc = pImmAssociateContextEx(hwnd, newimc, 0);
463 ok(rc, "ImmAssociateContextEx failed\n");
464 retimc = ImmGetContext(hwnd);
465 ok(retimc == newimc, "handles should be the same\n");
466 ImmReleaseContext(hwnd,retimc);
468 rc = pImmAssociateContextEx(hwnd, NULL, IACE_DEFAULT);
469 ok(rc, "ImmAssociateContextEx failed\n");
471 ImmReleaseContext(hwnd,imc);
474 typedef struct _igc_threadinfo {
475 HWND hwnd;
476 HANDLE event;
477 HIMC himc;
478 HIMC u_himc;
479 } igc_threadinfo;
482 static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
484 HIMC h1,h2;
485 HWND hwnd2;
486 COMPOSITIONFORM cf;
487 CANDIDATEFORM cdf;
488 POINT pt;
489 MSG msg;
491 igc_threadinfo *info= (igc_threadinfo*)lpParam;
492 info->hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
493 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
494 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
496 h1 = ImmGetContext(hwnd);
497 ok(info->himc == h1, "hwnd context changed in new thread\n");
498 h2 = ImmGetContext(info->hwnd);
499 ok(h2 != h1, "new hwnd in new thread should have different context\n");
500 info->himc = h2;
501 ImmReleaseContext(hwnd,h1);
503 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
504 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
505 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
506 h1 = ImmGetContext(hwnd2);
508 ok(h1 == h2, "Windows in same thread should have same default context\n");
509 ImmReleaseContext(hwnd2,h1);
510 ImmReleaseContext(info->hwnd,h2);
511 DestroyWindow(hwnd2);
513 /* priming for later tests */
514 ImmSetCompositionWindow(h1, &cf);
515 ImmSetStatusWindowPos(h1, &pt);
516 info->u_himc = ImmCreateContext();
517 ImmSetOpenStatus(info->u_himc, TRUE);
518 cdf.dwIndex = 0;
519 cdf.dwStyle = CFS_CANDIDATEPOS;
520 cdf.ptCurrentPos.x = 0;
521 cdf.ptCurrentPos.y = 0;
522 ImmSetCandidateWindow(info->u_himc, &cdf);
524 SetEvent(info->event);
526 while(GetMessageW(&msg, 0, 0, 0))
528 TranslateMessage(&msg);
529 DispatchMessageW(&msg);
531 return 1;
534 static void test_ImmThreads(void)
536 HIMC himc, otherHimc, h1;
537 igc_threadinfo threadinfo;
538 HANDLE hThread;
539 DWORD dwThreadId;
540 BOOL rc;
541 LOGFONTA lf;
542 COMPOSITIONFORM cf;
543 CANDIDATEFORM cdf;
544 DWORD status, sentence;
545 POINT pt;
547 himc = ImmGetContext(hwnd);
548 threadinfo.event = CreateEventA(NULL, TRUE, FALSE, NULL);
549 threadinfo.himc = himc;
550 hThread = CreateThread(NULL, 0, ImmGetContextThreadFunc, &threadinfo, 0, &dwThreadId );
551 WaitForSingleObject(threadinfo.event, INFINITE);
553 otherHimc = ImmGetContext(threadinfo.hwnd);
555 ok(himc != otherHimc, "Windows from other threads should have different himc\n");
556 ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n");
558 h1 = ImmAssociateContext(hwnd,otherHimc);
559 ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n");
560 h1 = ImmGetContext(hwnd);
561 ok(h1 == himc, "Context for window should remain unchanged\n");
562 ImmReleaseContext(hwnd,h1);
564 h1 = ImmAssociateContext(hwnd, threadinfo.u_himc);
565 ok (h1 == NULL, "Should fail to associate a context from a different thread\n");
566 h1 = ImmGetContext(hwnd);
567 ok(h1 == himc, "Context for window should remain unchanged\n");
568 ImmReleaseContext(hwnd,h1);
570 h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc);
571 ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n");
572 h1 = ImmGetContext(threadinfo.hwnd);
573 ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n");
574 ImmReleaseContext(threadinfo.hwnd,h1);
576 /* OpenStatus */
577 rc = ImmSetOpenStatus(himc, TRUE);
578 ok(rc != 0, "ImmSetOpenStatus failed\n");
579 rc = ImmGetOpenStatus(himc);
580 ok(rc != 0, "ImmGetOpenStatus failed\n");
581 rc = ImmSetOpenStatus(himc, FALSE);
582 ok(rc != 0, "ImmSetOpenStatus failed\n");
583 rc = ImmGetOpenStatus(himc);
584 ok(rc == 0, "ImmGetOpenStatus failed\n");
586 rc = ImmSetOpenStatus(otherHimc, TRUE);
587 ok(rc == 0, "ImmSetOpenStatus should fail\n");
588 rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE);
589 ok(rc == 0, "ImmSetOpenStatus should fail\n");
590 rc = ImmGetOpenStatus(otherHimc);
591 ok(rc == 0, "ImmGetOpenStatus failed\n");
592 rc = ImmGetOpenStatus(threadinfo.u_himc);
593 ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n");
594 rc = ImmSetOpenStatus(otherHimc, FALSE);
595 ok(rc == 0, "ImmSetOpenStatus should fail\n");
596 rc = ImmGetOpenStatus(otherHimc);
597 ok(rc == 0, "ImmGetOpenStatus failed\n");
599 /* CompositionFont */
600 rc = ImmGetCompositionFontA(himc, &lf);
601 ok(rc != 0, "ImmGetCompositionFont failed\n");
602 rc = ImmSetCompositionFontA(himc, &lf);
603 ok(rc != 0, "ImmSetCompositionFont failed\n");
605 rc = ImmGetCompositionFontA(otherHimc, &lf);
606 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n");
607 rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf);
608 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n");
609 rc = ImmSetCompositionFontA(otherHimc, &lf);
610 ok(rc == 0, "ImmSetCompositionFont should fail\n");
611 rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf);
612 ok(rc == 0, "ImmSetCompositionFont should fail\n");
614 /* CompositionWindow */
615 rc = ImmSetCompositionWindow(himc, &cf);
616 ok(rc != 0, "ImmSetCompositionWindow failed\n");
617 rc = ImmGetCompositionWindow(himc, &cf);
618 ok(rc != 0, "ImmGetCompositionWindow failed\n");
620 rc = ImmSetCompositionWindow(otherHimc, &cf);
621 ok(rc == 0, "ImmSetCompositionWindow should fail\n");
622 rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf);
623 ok(rc == 0, "ImmSetCompositionWindow should fail\n");
624 rc = ImmGetCompositionWindow(otherHimc, &cf);
625 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
626 rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf);
627 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
629 /* ConversionStatus */
630 rc = ImmGetConversionStatus(himc, &status, &sentence);
631 ok(rc != 0, "ImmGetConversionStatus failed\n");
632 rc = ImmSetConversionStatus(himc, status, sentence);
633 ok(rc != 0, "ImmSetConversionStatus failed\n");
635 rc = ImmGetConversionStatus(otherHimc, &status, &sentence);
636 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
637 rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence);
638 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
639 rc = ImmSetConversionStatus(otherHimc, status, sentence);
640 ok(rc == 0, "ImmSetConversionStatus should fail\n");
641 rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence);
642 ok(rc == 0, "ImmSetConversionStatus should fail\n");
644 /* StatusWindowPos */
645 rc = ImmSetStatusWindowPos(himc, &pt);
646 ok(rc != 0, "ImmSetStatusWindowPos failed\n");
647 rc = ImmGetStatusWindowPos(himc, &pt);
648 ok(rc != 0, "ImmGetStatusWindowPos failed\n");
650 rc = ImmSetStatusWindowPos(otherHimc, &pt);
651 ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
652 rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt);
653 ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
654 rc = ImmGetStatusWindowPos(otherHimc, &pt);
655 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
656 rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt);
657 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
659 h1 = ImmAssociateContext(threadinfo.hwnd, NULL);
660 ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n");
661 h1 = ImmGetContext(threadinfo.hwnd);
662 ok (h1 == NULL, "CrossThread window context should be NULL\n");
663 h1 = ImmAssociateContext(threadinfo.hwnd, h1);
664 ok (h1 == NULL, "Resetting cross thread context should fail\n");
665 h1 = ImmGetContext(threadinfo.hwnd);
666 ok (h1 == NULL, "CrossThread window context should still be NULL\n");
668 rc = ImmDestroyContext(threadinfo.u_himc);
669 ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n");
671 /* Candidate Window */
672 rc = ImmGetCandidateWindow(himc, 0, &cdf);
673 ok (rc == 0, "ImmGetCandidateWindow should fail\n");
674 cdf.dwIndex = 0;
675 cdf.dwStyle = CFS_CANDIDATEPOS;
676 cdf.ptCurrentPos.x = 0;
677 cdf.ptCurrentPos.y = 0;
678 rc = ImmSetCandidateWindow(himc, &cdf);
679 ok (rc == 1, "ImmSetCandidateWindow should succeed\n");
680 rc = ImmGetCandidateWindow(himc, 0, &cdf);
681 ok (rc == 1, "ImmGetCandidateWindow should succeed\n");
683 rc = ImmGetCandidateWindow(otherHimc, 0, &cdf);
684 ok (rc == 0, "ImmGetCandidateWindow should fail\n");
685 rc = ImmSetCandidateWindow(otherHimc, &cdf);
686 ok (rc == 0, "ImmSetCandidateWindow should fail\n");
687 rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf);
688 ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n");
689 rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf);
690 ok (rc == 0, "ImmSetCandidateWindow should fail\n");
692 ImmReleaseContext(threadinfo.hwnd,otherHimc);
693 ImmReleaseContext(hwnd,himc);
695 SendMessageA(threadinfo.hwnd, WM_CLOSE, 0, 0);
696 rc = PostThreadMessageA(dwThreadId, WM_QUIT, 1, 0);
697 ok(rc == 1, "PostThreadMessage should succeed\n");
698 WaitForSingleObject(hThread, INFINITE);
699 CloseHandle(hThread);
701 himc = ImmGetContext(GetDesktopWindow());
702 ok(himc == NULL, "Should not be able to get himc from other process window\n");
705 static void test_ImmIsUIMessage(void)
707 struct test
709 UINT msg;
710 BOOL ret;
713 static const struct test tests[] =
715 { WM_MOUSEMOVE, FALSE },
716 { WM_IME_STARTCOMPOSITION, TRUE },
717 { WM_IME_ENDCOMPOSITION, TRUE },
718 { WM_IME_COMPOSITION, TRUE },
719 { WM_IME_SETCONTEXT, TRUE },
720 { WM_IME_NOTIFY, TRUE },
721 { WM_IME_CONTROL, FALSE },
722 { WM_IME_COMPOSITIONFULL, TRUE },
723 { WM_IME_SELECT, TRUE },
724 { WM_IME_CHAR, FALSE },
725 { 0x287 /* FIXME */, TRUE },
726 { WM_IME_REQUEST, FALSE },
727 { WM_IME_KEYDOWN, FALSE },
728 { WM_IME_KEYUP, FALSE },
729 { 0, FALSE } /* mark the end */
732 UINT WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
733 UINT WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
734 UINT WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
735 UINT WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
736 UINT WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
737 UINT WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
738 UINT WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
740 const struct test *test;
741 BOOL ret;
743 if (!pImmIsUIMessageA) return;
745 for (test = tests; test->msg; test++)
747 msg_spy_flush_msgs();
748 ret = pImmIsUIMessageA(NULL, test->msg, 0, 0);
749 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg);
750 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x for NULL hwnd\n", test->msg);
752 ret = pImmIsUIMessageA(hwnd, test->msg, 0, 0);
753 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg);
754 if (ret)
755 ok(msg_spy_find_msg(test->msg) != NULL, "Windows does send 0x%x\n", test->msg);
756 else
757 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x\n", test->msg);
760 ret = pImmIsUIMessageA(NULL, WM_MSIME_SERVICE, 0, 0);
761 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n");
762 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTOPTIONS, 0, 0);
763 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n");
764 ret = pImmIsUIMessageA(NULL, WM_MSIME_MOUSE, 0, 0);
765 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n");
766 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTREQUEST, 0, 0);
767 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n");
768 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERT, 0, 0);
769 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n");
770 ret = pImmIsUIMessageA(NULL, WM_MSIME_QUERYPOSITION, 0, 0);
771 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n");
772 ret = pImmIsUIMessageA(NULL, WM_MSIME_DOCUMENTFEED, 0, 0);
773 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n");
776 static void test_ImmGetContext(void)
778 HIMC himc;
779 DWORD err;
781 SetLastError(0xdeadbeef);
782 himc = ImmGetContext((HWND)0xffffffff);
783 err = GetLastError();
784 ok(himc == NULL, "ImmGetContext succeeded\n");
785 ok(err == ERROR_INVALID_WINDOW_HANDLE, "got %u\n", err);
787 himc = ImmGetContext(hwnd);
788 ok(himc != NULL, "ImmGetContext failed\n");
789 ok(ImmReleaseContext(hwnd, himc), "ImmReleaseContext failed\n");
792 static void test_ImmGetDescription(void)
794 HKL hkl;
795 WCHAR descW[100];
796 CHAR descA[100];
797 UINT ret, lret;
799 /* FIXME: invalid keyboard layouts should not pass */
800 ret = ImmGetDescriptionW(NULL, NULL, 0);
801 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret);
802 ret = ImmGetDescriptionA(NULL, NULL, 0);
803 ok(!ret, "ImmGetDescriptionA failed, expected 0 received %d.\n", ret);
805 /* load a language with valid IMM descriptions */
806 hkl = GetKeyboardLayout(0);
807 ok(hkl != 0, "GetKeyboardLayout failed, expected != 0.\n");
809 ret = ImmGetDescriptionW(hkl, NULL, 0);
810 if(!ret)
812 win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n");
813 return;
816 SetLastError(0xdeadcafe);
817 ret = ImmGetDescriptionW(0, NULL, 100);
818 ok (ret == 0, "ImmGetDescriptionW with 0 hkl should return 0\n");
819 ret = GetLastError();
820 ok (ret == 0xdeadcafe, "Last Error should remain unchanged\n");
822 ret = ImmGetDescriptionW(hkl, descW, 0);
823 ok(ret, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
825 lret = ImmGetDescriptionW(hkl, descW, ret + 1);
826 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
827 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret);
829 lret = ImmGetDescriptionA(hkl, descA, ret + 1);
830 ok(lret, "ImmGetDescriptionA failed, expected != 0 received 0.\n");
831 ok(lret == ret, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret);
833 ret /= 2; /* try to copy partially */
834 lret = ImmGetDescriptionW(hkl, descW, ret + 1);
835 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
836 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret);
838 lret = ImmGetDescriptionA(hkl, descA, ret + 1);
839 ok(!lret, "ImmGetDescriptionA should fail\n");
841 ret = ImmGetDescriptionW(hkl, descW, 1);
842 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret);
844 UnloadKeyboardLayout(hkl);
847 static LRESULT (WINAPI *old_imm_wnd_proc)(HWND, UINT, WPARAM, LPARAM);
848 static LRESULT WINAPI imm_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
850 ok(msg != WM_DESTROY, "got WM_DESTROY message\n");
851 return old_imm_wnd_proc(hwnd, msg, wparam, lparam);
854 static HWND thread_ime_wnd;
855 static DWORD WINAPI test_ImmGetDefaultIMEWnd_thread(void *arg)
857 CreateWindowA("static", "static", WS_POPUP, 0, 0, 1, 1, NULL, NULL, NULL, NULL);
859 thread_ime_wnd = ImmGetDefaultIMEWnd(0);
860 ok(thread_ime_wnd != 0, "ImmGetDefaultIMEWnd returned NULL\n");
861 old_imm_wnd_proc = (void*)SetWindowLongPtrW(thread_ime_wnd, GWLP_WNDPROC, (LONG_PTR)imm_wnd_proc);
862 return 0;
865 static void test_ImmDefaultHwnd(void)
867 HIMC imc1, imc2, imc3;
868 HWND def1, def3;
869 HANDLE thread;
870 HWND hwnd;
872 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
873 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
874 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
876 ShowWindow(hwnd, SW_SHOWNORMAL);
878 imc1 = ImmGetContext(hwnd);
879 if (!imc1)
881 win_skip("IME support not implemented\n");
882 return;
885 def1 = ImmGetDefaultIMEWnd(hwnd);
887 imc2 = ImmCreateContext();
888 ImmSetOpenStatus(imc2, TRUE);
890 imc3 = ImmGetContext(hwnd);
891 def3 = ImmGetDefaultIMEWnd(hwnd);
893 ok(def3 == def1, "Default IME window should not change\n");
894 ok(imc1 == imc3, "IME context should not change\n");
895 ImmSetOpenStatus(imc2, FALSE);
897 thread = CreateThread(NULL, 0, test_ImmGetDefaultIMEWnd_thread, NULL, 0, NULL);
898 WaitForSingleObject(thread, INFINITE);
899 ok(thread_ime_wnd != def1, "thread_ime_wnd == def1\n");
900 ok(!IsWindow(thread_ime_wnd), "thread_ime_wnd was not destroyed\n");
901 CloseHandle(thread);
903 ImmReleaseContext(hwnd, imc1);
904 ImmReleaseContext(hwnd, imc3);
905 ImmDestroyContext(imc2);
906 DestroyWindow(hwnd);
909 static BOOL CALLBACK is_ime_window_proc(HWND hWnd, LPARAM param)
911 static const WCHAR imeW[] = {'I','M','E',0};
912 WCHAR class_nameW[16];
913 HWND *ime_window = (HWND *)param;
914 if (GetClassNameW(hWnd, class_nameW, sizeof(class_nameW)/sizeof(class_nameW[0])) &&
915 !lstrcmpW(class_nameW, imeW)) {
916 *ime_window = hWnd;
917 return FALSE;
919 return TRUE;
922 static HWND get_ime_window(void)
924 HWND ime_window = NULL;
925 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc, (LPARAM)&ime_window);
926 return ime_window;
929 struct testcase_ime_window {
930 BOOL visible;
931 BOOL top_level_window;
934 static DWORD WINAPI test_default_ime_window_cb(void *arg)
936 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg;
937 DWORD visible = testcase->visible ? WS_VISIBLE : 0;
938 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd;
940 ok(!get_ime_window(), "Expected no IME windows\n");
941 if (testcase->top_level_window) {
942 test_phase = FIRST_WINDOW;
943 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
944 WS_OVERLAPPEDWINDOW | visible,
945 CW_USEDEFAULT, CW_USEDEFAULT,
946 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
948 else {
949 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
950 WS_CHILD | visible,
951 CW_USEDEFAULT, CW_USEDEFAULT,
952 240, 24, hwnd, NULL, GetModuleHandleW(NULL), NULL);
954 ime_wnd = get_ime_window();
955 todo_wine ok(ime_wnd != NULL, "Expected IME window existence\n");
956 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1);
957 todo_wine ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
959 test_phase = SECOND_WINDOW;
960 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
961 WS_OVERLAPPEDWINDOW | visible,
962 CW_USEDEFAULT, CW_USEDEFAULT,
963 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
964 DestroyWindow(hwnd2);
965 todo_wine ok(IsWindow(ime_wnd) ||
966 broken(!testcase->visible /* Vista */) ||
967 broken(!testcase->top_level_window /* Vista */) ,
968 "Expected IME window existence\n");
969 DestroyWindow(hwnd1);
970 ok(!IsWindow(ime_wnd), "Expected no IME windows\n");
971 return 1;
974 static DWORD WINAPI test_default_ime_window_cancel_cb(void *arg)
976 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg;
977 DWORD visible = testcase->visible ? WS_VISIBLE : 0;
978 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd;
980 ok(!get_ime_window(), "Expected no IME windows\n");
981 test_phase = NCCREATE_CANCEL;
982 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
983 WS_OVERLAPPEDWINDOW | visible,
984 CW_USEDEFAULT, CW_USEDEFAULT,
985 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
986 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1);
987 ok(!get_ime_window(), "Expected no IME windows\n");
989 test_phase = CREATE_CANCEL;
990 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
991 WS_OVERLAPPEDWINDOW | visible,
992 CW_USEDEFAULT, CW_USEDEFAULT,
993 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
994 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1);
995 ok(!get_ime_window(), "Expected no IME windows\n");
997 test_phase = FIRST_WINDOW;
998 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
999 WS_OVERLAPPEDWINDOW | visible,
1000 CW_USEDEFAULT, CW_USEDEFAULT,
1001 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
1002 ime_wnd = get_ime_window();
1003 todo_wine ok(ime_wnd != NULL, "Expected IME window existence\n");
1004 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2);
1005 todo_wine ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
1007 DestroyWindow(hwnd2);
1008 ok(!IsWindow(ime_wnd), "Expected no IME windows\n");
1009 return 1;
1012 static DWORD WINAPI test_default_ime_disabled_cb(void *arg)
1014 HWND hWnd, default_ime_wnd;
1016 ok(!get_ime_window(), "Expected no IME windows\n");
1017 ImmDisableIME(GetCurrentThreadId());
1018 test_phase = IME_DISABLED;
1019 hWnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
1020 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1021 CW_USEDEFAULT, CW_USEDEFAULT,
1022 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
1023 default_ime_wnd = ImmGetDefaultIMEWnd(hWnd);
1024 ok(!default_ime_wnd, "Expected no IME windows\n");
1025 DestroyWindow(hWnd);
1026 return 1;
1029 static void test_default_ime_window_creation(void)
1031 HANDLE thread;
1032 size_t i;
1033 struct testcase_ime_window testcases[] = {
1034 /* visible, top-level window */
1035 { TRUE, TRUE },
1036 { FALSE, TRUE },
1037 { TRUE, FALSE },
1038 { FALSE, FALSE }
1041 for (i = 0; i < sizeof(testcases)/sizeof(testcases[0]); i++)
1043 thread = CreateThread(NULL, 0, test_default_ime_window_cb, &testcases[i], 0, NULL);
1044 ok(thread != NULL, "CreateThread failed with error %u\n", GetLastError());
1045 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
1047 MSG msg;
1048 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1050 TranslateMessage(&msg);
1051 DispatchMessageA(&msg);
1054 CloseHandle(thread);
1056 if (testcases[i].top_level_window)
1058 thread = CreateThread(NULL, 0, test_default_ime_window_cancel_cb, &testcases[i], 0, NULL);
1059 ok(thread != NULL, "CreateThread failed with error %u\n", GetLastError());
1060 WaitForSingleObject(thread, INFINITE);
1061 CloseHandle(thread);
1065 thread = CreateThread(NULL, 0, test_default_ime_disabled_cb, NULL, 0, NULL);
1066 WaitForSingleObject(thread, INFINITE);
1067 CloseHandle(thread);
1069 test_phase = PHASE_UNKNOWN;
1072 static void test_ImmGetIMCLockCount(void)
1074 HIMC imc;
1075 DWORD count, ret, i;
1076 INPUTCONTEXT *ic;
1078 imc = ImmCreateContext();
1079 ImmDestroyContext(imc);
1080 SetLastError(0xdeadbeef);
1081 count = ImmGetIMCLockCount((HIMC)0xdeadcafe);
1082 ok(count == 0, "Invalid IMC should return 0\n");
1083 ret = GetLastError();
1084 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1085 SetLastError(0xdeadbeef);
1086 count = ImmGetIMCLockCount(0x00000000);
1087 ok(count == 0, "NULL IMC should return 0\n");
1088 ret = GetLastError();
1089 ok(ret == 0xdeadbeef, "Last Error should remain unchanged: %08x\n",ret);
1090 count = ImmGetIMCLockCount(imc);
1091 ok(count == 0, "Destroyed IMC should return 0\n");
1092 ret = GetLastError();
1093 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1095 imc = ImmCreateContext();
1096 count = ImmGetIMCLockCount(imc);
1097 ok(count == 0, "expect 0, returned %d\n", count);
1098 ic = ImmLockIMC(imc);
1099 ok(ic != NULL, "ImmLockIMC failed!\n");
1100 count = ImmGetIMCLockCount(imc);
1101 ok(count == 1, "expect 1, returned %d\n", count);
1102 ret = ImmUnlockIMC(imc);
1103 ok(ret == TRUE, "expect TRUE, ret %d\n", ret);
1104 count = ImmGetIMCLockCount(imc);
1105 ok(count == 0, "expect 0, returned %d\n", count);
1106 ret = ImmUnlockIMC(imc);
1107 ok(ret == TRUE, "expect TRUE, ret %d\n", ret);
1108 count = ImmGetIMCLockCount(imc);
1109 ok(count == 0, "expect 0, returned %d\n", count);
1111 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++)
1113 ic = ImmLockIMC(imc);
1114 ok(ic != NULL, "ImmLockIMC failed!\n");
1116 count = ImmGetIMCLockCount(imc);
1117 todo_wine ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %d\n", count);
1119 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++)
1120 ImmUnlockIMC(imc);
1121 count = ImmGetIMCLockCount(imc);
1122 todo_wine ok(count == 1, "expect 1, returned %d\n", count);
1123 ImmUnlockIMC(imc);
1124 count = ImmGetIMCLockCount(imc);
1125 todo_wine ok(count == 0, "expect 0, returned %d\n", count);
1127 ImmDestroyContext(imc);
1130 static void test_ImmGetIMCCLockCount(void)
1132 HIMCC imcc;
1133 DWORD count, g_count, i;
1134 BOOL ret;
1135 VOID *p;
1137 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO));
1138 count = ImmGetIMCCLockCount(imcc);
1139 ok(count == 0, "expect 0, returned %d\n", count);
1140 ImmLockIMCC(imcc);
1141 count = ImmGetIMCCLockCount(imcc);
1142 ok(count == 1, "expect 1, returned %d\n", count);
1143 ret = ImmUnlockIMCC(imcc);
1144 ok(ret == FALSE, "expect FALSE, ret %d\n", ret);
1145 count = ImmGetIMCCLockCount(imcc);
1146 ok(count == 0, "expect 0, returned %d\n", count);
1147 ret = ImmUnlockIMCC(imcc);
1148 ok(ret == FALSE, "expect FALSE, ret %d\n", ret);
1149 count = ImmGetIMCCLockCount(imcc);
1150 ok(count == 0, "expect 0, returned %d\n", count);
1152 p = ImmLockIMCC(imcc);
1153 ok(GlobalHandle(p) == imcc, "expect %p, returned %p\n", imcc, GlobalHandle(p));
1155 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++)
1157 ImmLockIMCC(imcc);
1158 count = ImmGetIMCCLockCount(imcc);
1159 g_count = GlobalFlags(imcc) & GMEM_LOCKCOUNT;
1160 ok(count == g_count, "count %d, g_count %d\n", count, g_count);
1162 count = ImmGetIMCCLockCount(imcc);
1163 ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %d\n", count);
1165 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++)
1166 GlobalUnlock(imcc);
1167 count = ImmGetIMCCLockCount(imcc);
1168 ok(count == 1, "expect 1, returned %d\n", count);
1169 GlobalUnlock(imcc);
1170 count = ImmGetIMCCLockCount(imcc);
1171 ok(count == 0, "expect 0, returned %d\n", count);
1173 ImmDestroyIMCC(imcc);
1176 static void test_ImmDestroyContext(void)
1178 HIMC imc;
1179 DWORD ret, count;
1180 INPUTCONTEXT *ic;
1182 imc = ImmCreateContext();
1183 count = ImmGetIMCLockCount(imc);
1184 ok(count == 0, "expect 0, returned %d\n", count);
1185 ic = ImmLockIMC(imc);
1186 ok(ic != NULL, "ImmLockIMC failed!\n");
1187 count = ImmGetIMCLockCount(imc);
1188 ok(count == 1, "expect 1, returned %d\n", count);
1189 ret = ImmDestroyContext(imc);
1190 ok(ret == TRUE, "Destroy a locked IMC should success!\n");
1191 ic = ImmLockIMC(imc);
1192 ok(ic == NULL, "Lock a destroyed IMC should fail!\n");
1193 ret = ImmUnlockIMC(imc);
1194 ok(ret == FALSE, "Unlock a destroyed IMC should fail!\n");
1195 count = ImmGetIMCLockCount(imc);
1196 ok(count == 0, "Get lock count of a destroyed IMC should return 0!\n");
1197 SetLastError(0xdeadbeef);
1198 ret = ImmDestroyContext(imc);
1199 ok(ret == FALSE, "Destroy a destroyed IMC should fail!\n");
1200 ret = GetLastError();
1201 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1204 static void test_ImmDestroyIMCC(void)
1206 HIMCC imcc;
1207 DWORD ret, count, size;
1208 VOID *p;
1210 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO));
1211 count = ImmGetIMCCLockCount(imcc);
1212 ok(count == 0, "expect 0, returned %d\n", count);
1213 p = ImmLockIMCC(imcc);
1214 ok(p != NULL, "ImmLockIMCC failed!\n");
1215 count = ImmGetIMCCLockCount(imcc);
1216 ok(count == 1, "expect 1, returned %d\n", count);
1217 size = ImmGetIMCCSize(imcc);
1218 ok(size == sizeof(CANDIDATEINFO), "returned %d\n", size);
1219 p = ImmDestroyIMCC(imcc);
1220 ok(p == NULL, "Destroy a locked IMCC should success!\n");
1221 p = ImmLockIMCC(imcc);
1222 ok(p == NULL, "Lock a destroyed IMCC should fail!\n");
1223 ret = ImmUnlockIMCC(imcc);
1224 ok(ret == FALSE, "Unlock a destroyed IMCC should return FALSE!\n");
1225 count = ImmGetIMCCLockCount(imcc);
1226 ok(count == 0, "Get lock count of a destroyed IMCC should return 0!\n");
1227 size = ImmGetIMCCSize(imcc);
1228 ok(size == 0, "Get size of a destroyed IMCC should return 0!\n");
1229 SetLastError(0xdeadbeef);
1230 p = ImmDestroyIMCC(imcc);
1231 ok(p != NULL, "returned NULL\n");
1232 ret = GetLastError();
1233 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1236 static void test_ImmMessages(void)
1238 CANDIDATEFORM cf;
1239 imm_msgs *msg;
1240 HWND defwnd;
1241 HIMC imc;
1242 UINT idx = 0;
1244 LPINPUTCONTEXT lpIMC;
1245 LPTRANSMSG lpTransMsg;
1247 HWND hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
1248 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
1249 240, 120, NULL, NULL, GetModuleHandleA(NULL), NULL);
1251 ShowWindow(hwnd, SW_SHOWNORMAL);
1252 defwnd = ImmGetDefaultIMEWnd(hwnd);
1253 imc = ImmGetContext(hwnd);
1255 ImmSetOpenStatus(imc, TRUE);
1256 msg_spy_flush_msgs();
1257 SendMessageA(defwnd, WM_IME_CONTROL, IMC_GETCANDIDATEPOS, (LPARAM)&cf );
1260 msg = msg_spy_find_next_msg(WM_IME_CONTROL,&idx);
1261 if (msg) ok(!msg->post, "Message should not be posted\n");
1262 } while (msg);
1263 msg_spy_flush_msgs();
1265 lpIMC = ImmLockIMC(imc);
1266 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
1267 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
1268 lpTransMsg += lpIMC->dwNumMsgBuf;
1269 lpTransMsg->message = WM_IME_STARTCOMPOSITION;
1270 lpTransMsg->wParam = 0;
1271 lpTransMsg->lParam = 0;
1272 ImmUnlockIMCC(lpIMC->hMsgBuf);
1273 lpIMC->dwNumMsgBuf++;
1274 ImmUnlockIMC(imc);
1275 ImmGenerateMessage(imc);
1276 idx = 0;
1279 msg = msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION, &idx);
1280 if (msg) ok(!msg->post, "Message should not be posted\n");
1281 } while (msg);
1282 msg_spy_flush_msgs();
1284 lpIMC = ImmLockIMC(imc);
1285 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
1286 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
1287 lpTransMsg += lpIMC->dwNumMsgBuf;
1288 lpTransMsg->message = WM_IME_COMPOSITION;
1289 lpTransMsg->wParam = 0;
1290 lpTransMsg->lParam = 0;
1291 ImmUnlockIMCC(lpIMC->hMsgBuf);
1292 lpIMC->dwNumMsgBuf++;
1293 ImmUnlockIMC(imc);
1294 ImmGenerateMessage(imc);
1295 idx = 0;
1298 msg = msg_spy_find_next_msg(WM_IME_COMPOSITION, &idx);
1299 if (msg) ok(!msg->post, "Message should not be posted\n");
1300 } while (msg);
1301 msg_spy_flush_msgs();
1303 lpIMC = ImmLockIMC(imc);
1304 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
1305 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
1306 lpTransMsg += lpIMC->dwNumMsgBuf;
1307 lpTransMsg->message = WM_IME_ENDCOMPOSITION;
1308 lpTransMsg->wParam = 0;
1309 lpTransMsg->lParam = 0;
1310 ImmUnlockIMCC(lpIMC->hMsgBuf);
1311 lpIMC->dwNumMsgBuf++;
1312 ImmUnlockIMC(imc);
1313 ImmGenerateMessage(imc);
1314 idx = 0;
1317 msg = msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION, &idx);
1318 if (msg) ok(!msg->post, "Message should not be posted\n");
1319 } while (msg);
1320 msg_spy_flush_msgs();
1322 ImmSetOpenStatus(imc, FALSE);
1323 ImmReleaseContext(hwnd, imc);
1324 DestroyWindow(hwnd);
1327 static LRESULT CALLBACK processkey_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam,
1328 LPARAM lParam )
1330 return DefWindowProcW(hWnd, msg, wParam, lParam);
1333 static void test_ime_processkey(void)
1335 WCHAR classNameW[] = {'P','r','o','c','e','s','s', 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1336 WCHAR windowNameW[] = {'P','r','o','c','e','s','s', 'K','e','y',0};
1338 MSG msg;
1339 WNDCLASSW wclass;
1340 HANDLE hInstance = GetModuleHandleW(NULL);
1341 TEST_INPUT inputs[2];
1342 HIMC imc;
1343 INT rc;
1344 HWND hWndTest;
1346 wclass.lpszClassName = classNameW;
1347 wclass.style = CS_HREDRAW | CS_VREDRAW;
1348 wclass.lpfnWndProc = processkey_wnd_proc;
1349 wclass.hInstance = hInstance;
1350 wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
1351 wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW);
1352 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1353 wclass.lpszMenuName = 0;
1354 wclass.cbClsExtra = 0;
1355 wclass.cbWndExtra = 0;
1356 if(!RegisterClassW(&wclass)){
1357 win_skip("Failed to register window.\n");
1358 return;
1361 /* create the test window that will receive the keystrokes */
1362 hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW,
1363 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
1364 NULL, NULL, hInstance, NULL);
1366 ShowWindow(hWndTest, SW_SHOW);
1367 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1368 SetForegroundWindow(hWndTest);
1369 UpdateWindow(hWndTest);
1371 imc = ImmGetContext(hWndTest);
1372 if (!imc)
1374 win_skip("IME not supported\n");
1375 DestroyWindow(hWndTest);
1376 return;
1379 rc = ImmSetOpenStatus(imc, TRUE);
1380 if (rc != TRUE)
1382 win_skip("Unable to open IME\n");
1383 ImmReleaseContext(hWndTest, imc);
1384 DestroyWindow(hWndTest);
1385 return;
1388 /* flush pending messages */
1389 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
1391 SetFocus(hWndTest);
1393 /* init input data that never changes */
1394 inputs[1].type = inputs[0].type = INPUT_KEYBOARD;
1395 inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0;
1396 inputs[1].u.ki.time = inputs[0].u.ki.time = 0;
1398 /* Pressing a key */
1399 inputs[0].u.ki.wVk = 0x41;
1400 inputs[0].u.ki.wScan = 0x1e;
1401 inputs[0].u.ki.dwFlags = 0x0;
1403 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
1405 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) {
1406 if(msg.message != WM_KEYDOWN)
1407 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
1408 else
1410 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n");
1411 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
1412 if(msg.wParam == VK_PROCESSKEY)
1413 trace("ProcessKey was correctly found\n");
1415 TranslateMessage(&msg);
1416 DispatchMessageW(&msg);
1419 inputs[0].u.ki.wVk = 0x41;
1420 inputs[0].u.ki.wScan = 0x1e;
1421 inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP;
1423 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
1425 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) {
1426 if(msg.message != WM_KEYUP)
1427 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
1428 else
1430 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n");
1431 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
1432 ok(msg.wParam != VK_PROCESSKEY,"ProcessKey should still not be Found\n");
1434 TranslateMessage(&msg);
1435 DispatchMessageW(&msg);
1438 ImmReleaseContext(hWndTest, imc);
1439 ImmSetOpenStatus(imc, FALSE);
1440 DestroyWindow(hWndTest);
1443 static void test_InvalidIMC(void)
1445 HIMC imc_destroy;
1446 HIMC imc_null = 0x00000000;
1447 HIMC imc_bad = (HIMC)0xdeadcafe;
1449 HIMC imc1, imc2, oldimc;
1450 DWORD ret;
1451 DWORD count;
1452 CHAR buffer[1000];
1453 INPUTCONTEXT *ic;
1454 LOGFONTA lf;
1456 memset(&lf, 0, sizeof(lf));
1458 imc_destroy = ImmCreateContext();
1459 ret = ImmDestroyContext(imc_destroy);
1460 ok(ret == TRUE, "Destroy an IMC should success!\n");
1462 /* Test associating destroyed imc */
1463 imc1 = ImmGetContext(hwnd);
1464 SetLastError(0xdeadbeef);
1465 oldimc = ImmAssociateContext(hwnd, imc_destroy);
1466 ok(!oldimc, "Associating to a destroyed imc should fail!\n");
1467 ret = GetLastError();
1468 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1469 imc2 = ImmGetContext(hwnd);
1470 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2);
1472 /* Test associating NULL imc, which is different from an invalid imc */
1473 oldimc = ImmAssociateContext(hwnd, imc_null);
1474 ok(oldimc != NULL, "Associating to NULL imc should success!\n");
1475 imc2 = ImmGetContext(hwnd);
1476 ok(!imc2, "expect NULL, returned %p\n", imc2);
1477 oldimc = ImmAssociateContext(hwnd, imc1);
1478 ok(!oldimc, "expect NULL, returned %p\n", oldimc);
1479 imc2 = ImmGetContext(hwnd);
1480 ok(imc2 == imc1, "imc should not changed! imc2 %p, imc1 %p\n", imc2, imc1);
1482 /* Test associating invalid imc */
1483 imc1 = ImmGetContext(hwnd);
1484 SetLastError(0xdeadbeef);
1485 oldimc = ImmAssociateContext(hwnd, imc_bad);
1486 ok(!oldimc, "Associating to a destroyed imc should fail!\n");
1487 ret = GetLastError();
1488 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1489 imc2 = ImmGetContext(hwnd);
1490 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2);
1493 /* Test ImmGetCandidateListA */
1494 SetLastError(0xdeadbeef);
1495 ret = ImmGetCandidateListA(imc_bad, 0, NULL, 0);
1496 ok(ret == 0, "Bad IME should return 0\n");
1497 ret = GetLastError();
1498 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1499 SetLastError(0xdeadbeef);
1500 ret = ImmGetCandidateListA(imc_null, 0, NULL, 0);
1501 ok(ret == 0, "NULL IME should return 0\n");
1502 ret = GetLastError();
1503 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1504 SetLastError(0xdeadbeef);
1505 ret = ImmGetCandidateListA(imc_destroy, 0, NULL, 0);
1506 ok(ret == 0, "Destroyed IME should return 0\n");
1507 ret = GetLastError();
1508 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1510 /* Test ImmGetCandidateListCountA*/
1511 SetLastError(0xdeadbeef);
1512 ret = ImmGetCandidateListCountA(imc_bad,&count);
1513 ok(ret == 0, "Bad IME should return 0\n");
1514 ret = GetLastError();
1515 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1516 SetLastError(0xdeadbeef);
1517 ret = ImmGetCandidateListCountA(imc_null,&count);
1518 ok(ret == 0, "NULL IME should return 0\n");
1519 ret = GetLastError();
1520 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1521 SetLastError(0xdeadbeef);
1522 ret = ImmGetCandidateListCountA(imc_destroy,&count);
1523 ok(ret == 0, "Destroyed IME should return 0\n");
1524 ret = GetLastError();
1525 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1527 /* Test ImmGetCandidateWindow */
1528 SetLastError(0xdeadbeef);
1529 ret = ImmGetCandidateWindow(imc_bad, 0, (LPCANDIDATEFORM)buffer);
1530 ok(ret == 0, "Bad IME should return 0\n");
1531 ret = GetLastError();
1532 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1533 SetLastError(0xdeadbeef);
1534 ret = ImmGetCandidateWindow(imc_null, 0, (LPCANDIDATEFORM)buffer);
1535 ok(ret == 0, "NULL IME should return 0\n");
1536 ret = GetLastError();
1537 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1538 SetLastError(0xdeadbeef);
1539 ret = ImmGetCandidateWindow(imc_destroy, 0, (LPCANDIDATEFORM)buffer);
1540 ok(ret == 0, "Destroyed IME should return 0\n");
1541 ret = GetLastError();
1542 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1544 /* Test ImmGetCompositionFontA */
1545 SetLastError(0xdeadbeef);
1546 ret = ImmGetCompositionFontA(imc_bad, (LPLOGFONTA)buffer);
1547 ok(ret == 0, "Bad IME should return 0\n");
1548 ret = GetLastError();
1549 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1550 SetLastError(0xdeadbeef);
1551 ret = ImmGetCompositionFontA(imc_null, (LPLOGFONTA)buffer);
1552 ok(ret == 0, "NULL IME should return 0\n");
1553 ret = GetLastError();
1554 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1555 SetLastError(0xdeadbeef);
1556 ret = ImmGetCompositionFontA(imc_destroy, (LPLOGFONTA)buffer);
1557 ok(ret == 0, "Destroyed IME should return 0\n");
1558 ret = GetLastError();
1559 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1561 /* Test ImmGetCompositionWindow */
1562 SetLastError(0xdeadbeef);
1563 ret = ImmGetCompositionWindow(imc_bad, (LPCOMPOSITIONFORM)buffer);
1564 ok(ret == 0, "Bad IME should return 0\n");
1565 ret = GetLastError();
1566 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1567 SetLastError(0xdeadbeef);
1568 ret = ImmGetCompositionWindow(imc_null, (LPCOMPOSITIONFORM)buffer);
1569 ok(ret == 0, "NULL IME should return 0\n");
1570 ret = GetLastError();
1571 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1572 SetLastError(0xdeadbeef);
1573 ret = ImmGetCompositionWindow(imc_destroy, (LPCOMPOSITIONFORM)buffer);
1574 ok(ret == 0, "Destroyed IME should return 0\n");
1575 ret = GetLastError();
1576 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1578 /* Test ImmGetCompositionStringA */
1579 SetLastError(0xdeadbeef);
1580 ret = ImmGetCompositionStringA(imc_bad, GCS_COMPSTR, NULL, 0);
1581 ok(ret == 0, "Bad IME should return 0\n");
1582 ret = GetLastError();
1583 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1584 SetLastError(0xdeadbeef);
1585 ret = ImmGetCompositionStringA(imc_null, GCS_COMPSTR, NULL, 0);
1586 ok(ret == 0, "NULL IME should return 0\n");
1587 ret = GetLastError();
1588 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1589 SetLastError(0xdeadbeef);
1590 ret = ImmGetCompositionStringA(imc_destroy, GCS_COMPSTR, NULL, 0);
1591 ok(ret == 0, "Destroyed IME should return 0\n");
1592 ret = GetLastError();
1593 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1595 /* Test ImmSetOpenStatus */
1596 SetLastError(0xdeadbeef);
1597 ret = ImmSetOpenStatus(imc_bad, 1);
1598 ok(ret == 0, "Bad IME should return 0\n");
1599 ret = GetLastError();
1600 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1601 SetLastError(0xdeadbeef);
1602 ret = ImmSetOpenStatus(imc_null, 1);
1603 ok(ret == 0, "NULL IME should return 0\n");
1604 ret = GetLastError();
1605 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1606 SetLastError(0xdeadbeef);
1607 ret = ImmSetOpenStatus(imc_destroy, 1);
1608 ok(ret == 0, "Destroyed IME should return 0\n");
1609 ret = GetLastError();
1610 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1612 /* Test ImmGetOpenStatus */
1613 SetLastError(0xdeadbeef);
1614 ret = ImmGetOpenStatus(imc_bad);
1615 ok(ret == 0, "Bad IME should return 0\n");
1616 ret = GetLastError();
1617 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1618 SetLastError(0xdeadbeef);
1619 ret = ImmGetOpenStatus(imc_null);
1620 ok(ret == 0, "NULL IME should return 0\n");
1621 ret = GetLastError();
1622 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1623 SetLastError(0xdeadbeef);
1624 ret = ImmGetOpenStatus(imc_destroy);
1625 ok(ret == 0, "Destroyed IME should return 0\n");
1626 ret = GetLastError();
1627 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1629 /* Test ImmGetStatusWindowPos */
1630 SetLastError(0xdeadbeef);
1631 ret = ImmGetStatusWindowPos(imc_bad, NULL);
1632 ok(ret == 0, "Bad IME should return 0\n");
1633 ret = GetLastError();
1634 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1635 SetLastError(0xdeadbeef);
1636 ret = ImmGetStatusWindowPos(imc_null, NULL);
1637 ok(ret == 0, "NULL IME should return 0\n");
1638 ret = GetLastError();
1639 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1640 SetLastError(0xdeadbeef);
1641 ret = ImmGetStatusWindowPos(imc_destroy, NULL);
1642 ok(ret == 0, "Destroyed IME should return 0\n");
1643 ret = GetLastError();
1644 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1646 /* Test ImmRequestMessageA */
1647 SetLastError(0xdeadbeef);
1648 ret = ImmRequestMessageA(imc_bad, WM_CHAR, 0);
1649 ok(ret == 0, "Bad IME should return 0\n");
1650 ret = GetLastError();
1651 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1652 SetLastError(0xdeadbeef);
1653 ret = ImmRequestMessageA(imc_null, WM_CHAR, 0);
1654 ok(ret == 0, "NULL IME should return 0\n");
1655 ret = GetLastError();
1656 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1657 SetLastError(0xdeadbeef);
1658 ret = ImmRequestMessageA(imc_destroy, WM_CHAR, 0);
1659 ok(ret == 0, "Destroyed IME should return 0\n");
1660 ret = GetLastError();
1661 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1663 /* Test ImmSetCompositionFontA */
1664 SetLastError(0xdeadbeef);
1665 ret = ImmSetCompositionFontA(imc_bad, &lf);
1666 ok(ret == 0, "Bad IME should return 0\n");
1667 ret = GetLastError();
1668 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1669 SetLastError(0xdeadbeef);
1670 ret = ImmSetCompositionFontA(imc_null, &lf);
1671 ok(ret == 0, "NULL IME should return 0\n");
1672 ret = GetLastError();
1673 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1674 SetLastError(0xdeadbeef);
1675 ret = ImmSetCompositionFontA(imc_destroy, &lf);
1676 ok(ret == 0, "Destroyed IME should return 0\n");
1677 ret = GetLastError();
1678 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1680 /* Test ImmSetCompositionWindow */
1681 SetLastError(0xdeadbeef);
1682 ret = ImmSetCompositionWindow(imc_bad, NULL);
1683 ok(ret == 0, "Bad IME should return 0\n");
1684 ret = GetLastError();
1685 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1686 SetLastError(0xdeadbeef);
1687 ret = ImmSetCompositionWindow(imc_null, NULL);
1688 ok(ret == 0, "NULL IME should return 0\n");
1689 ret = GetLastError();
1690 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1691 SetLastError(0xdeadbeef);
1692 ret = ImmSetCompositionWindow(imc_destroy, NULL);
1693 ok(ret == 0, "Destroyed IME should return 0\n");
1694 ret = GetLastError();
1695 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1697 /* Test ImmSetConversionStatus */
1698 SetLastError(0xdeadbeef);
1699 ret = ImmSetConversionStatus(imc_bad, 0, 0);
1700 ok(ret == 0, "Bad IME should return 0\n");
1701 ret = GetLastError();
1702 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1703 SetLastError(0xdeadbeef);
1704 ret = ImmSetConversionStatus(imc_null, 0, 0);
1705 ok(ret == 0, "NULL IME should return 0\n");
1706 ret = GetLastError();
1707 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1708 SetLastError(0xdeadbeef);
1709 ret = ImmSetConversionStatus(imc_destroy, 0, 0);
1710 ok(ret == 0, "Destroyed IME should return 0\n");
1711 ret = GetLastError();
1712 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1714 /* Test ImmSetStatusWindowPos */
1715 SetLastError(0xdeadbeef);
1716 ret = ImmSetStatusWindowPos(imc_bad, 0);
1717 ok(ret == 0, "Bad IME should return 0\n");
1718 ret = GetLastError();
1719 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1720 SetLastError(0xdeadbeef);
1721 ret = ImmSetStatusWindowPos(imc_null, 0);
1722 ok(ret == 0, "NULL IME should return 0\n");
1723 ret = GetLastError();
1724 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1725 SetLastError(0xdeadbeef);
1726 ret = ImmSetStatusWindowPos(imc_destroy, 0);
1727 ok(ret == 0, "Destroyed IME should return 0\n");
1728 ret = GetLastError();
1729 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1731 /* Test ImmGetImeMenuItemsA */
1732 SetLastError(0xdeadbeef);
1733 ret = ImmGetImeMenuItemsA(imc_bad, 0, 0, NULL, NULL, 0);
1734 ok(ret == 0, "Bad IME should return 0\n");
1735 ret = GetLastError();
1736 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1737 SetLastError(0xdeadbeef);
1738 ret = ImmGetImeMenuItemsA(imc_null, 0, 0, NULL, NULL, 0);
1739 ok(ret == 0, "NULL IME should return 0\n");
1740 ret = GetLastError();
1741 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1742 SetLastError(0xdeadbeef);
1743 ret = ImmGetImeMenuItemsA(imc_destroy, 0, 0, NULL, NULL, 0);
1744 ok(ret == 0, "Destroyed IME should return 0\n");
1745 ret = GetLastError();
1746 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1748 /* Test ImmLockIMC */
1749 SetLastError(0xdeadbeef);
1750 ic = ImmLockIMC(imc_bad);
1751 ok(ic == 0, "Bad IME should return 0\n");
1752 ret = GetLastError();
1753 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1754 SetLastError(0xdeadbeef);
1755 ic = ImmLockIMC(imc_null);
1756 ok(ic == 0, "NULL IME should return 0\n");
1757 ret = GetLastError();
1758 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1759 SetLastError(0xdeadbeef);
1760 ic = ImmLockIMC(imc_destroy);
1761 ok(ic == 0, "Destroyed IME should return 0\n");
1762 ret = GetLastError();
1763 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1765 /* Test ImmUnlockIMC */
1766 SetLastError(0xdeadbeef);
1767 ret = ImmUnlockIMC(imc_bad);
1768 ok(ret == 0, "Bad IME should return 0\n");
1769 ret = GetLastError();
1770 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1771 SetLastError(0xdeadbeef);
1772 ret = ImmUnlockIMC(imc_null);
1773 ok(ret == 0, "NULL IME should return 0\n");
1774 ret = GetLastError();
1775 ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
1776 SetLastError(0xdeadbeef);
1777 ret = ImmUnlockIMC(imc_destroy);
1778 ok(ret == 0, "Destroyed IME should return 0\n");
1779 ret = GetLastError();
1780 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1782 /* Test ImmGenerateMessage */
1783 SetLastError(0xdeadbeef);
1784 ret = ImmGenerateMessage(imc_bad);
1785 ok(ret == 0, "Bad IME should return 0\n");
1786 ret = GetLastError();
1787 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1788 SetLastError(0xdeadbeef);
1789 ret = ImmGenerateMessage(imc_null);
1790 ok(ret == 0, "NULL IME should return 0\n");
1791 ret = GetLastError();
1792 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1793 SetLastError(0xdeadbeef);
1794 ret = ImmGenerateMessage(imc_destroy);
1795 ok(ret == 0, "Destroyed IME should return 0\n");
1796 ret = GetLastError();
1797 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1800 START_TEST(imm32) {
1801 if (init())
1803 test_ImmNotifyIME();
1804 test_ImmGetCompositionString();
1805 test_ImmSetCompositionString();
1806 test_ImmIME();
1807 test_ImmAssociateContextEx();
1808 test_ImmThreads();
1809 test_ImmIsUIMessage();
1810 test_ImmGetContext();
1811 test_ImmGetDescription();
1812 test_ImmDefaultHwnd();
1813 test_default_ime_window_creation();
1814 test_ImmGetIMCLockCount();
1815 test_ImmGetIMCCLockCount();
1816 test_ImmDestroyContext();
1817 test_ImmDestroyIMCC();
1818 test_InvalidIMC();
1819 msg_spy_cleanup();
1820 /* Reinitialize the hooks to capture all windows */
1821 msg_spy_init(NULL);
1822 test_ImmMessages();
1823 msg_spy_cleanup();
1824 if (pSendInput)
1825 test_ime_processkey();
1826 else win_skip("SendInput is not available\n");
1828 cleanup();