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
23 #include "wine/test.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
{
43 static struct _msg_spy
{
46 HHOOK call_wnd_proc_hook
;
62 typedef struct _tagTRANSMSG
{
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
;
87 return CallNextHookEx(msg_spy
.get_msg_hook
, nCode
, wParam
, lParam
);
90 static LRESULT CALLBACK
call_wnd_proc_filter(int nCode
, WPARAM wParam
,
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
;
105 return CallNextHookEx(msg_spy
.call_wnd_proc_hook
, nCode
, wParam
, lParam
);
108 static void msg_spy_pump_msg_queue(void) {
111 while(PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
112 TranslateMessage(&msg
);
113 DispatchMessageW(&msg
);
119 static void msg_spy_flush_msgs(void) {
120 msg_spy_pump_msg_queue();
124 static imm_msgs
* msg_spy_find_next_msg(UINT message
, UINT
*start
) {
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",
133 for (i
= *start
; i
< msg_spy
.i_msg
; i
++)
134 if (msg_spy
.msgs
[i
].msg
.message
== message
)
137 return &msg_spy
.msgs
[i
];
143 static imm_msgs
* msg_spy_find_msg(UINT message
) {
146 return msg_spy_find_next_msg(message
, &i
);
149 static void msg_spy_init(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());
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
;
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
;
186 case WM_IME_SETCONTEXT
:
189 default_ime_wnd
= get_ime_window();
193 ok(!default_ime_wnd
, "expected no IME windows\n");
196 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
199 break; /* do nothing */
201 if (test_phase
== NCCREATE_CANCEL
)
205 default_ime_wnd
= get_ime_window();
210 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
213 ok(!default_ime_wnd
, "expected no IME windows\n");
216 break; /* do nothing */
220 default_ime_wnd
= get_ime_window();
225 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
228 ok(!default_ime_wnd
, "expected no IME windows\n");
231 break; /* do nothing */
233 if (test_phase
== CREATE_CANCEL
)
238 return DefWindowProcA(hWnd
,msg
,wParam
,lParam
);
241 static BOOL
init(void) {
246 hmod
= GetModuleHandleA("imm32.dll");
247 huser
= GetModuleHandleA("user32");
248 pImmAssociateContextEx
= (void*)GetProcAddress(hmod
, "ImmAssociateContextEx");
249 pImmIsUIMessageA
= (void*)GetProcAddress(hmod
, "ImmIsUIMessageA");
250 pSendInput
= (void*)GetProcAddress(huser
, "SendInput");
252 wc
.cbSize
= sizeof(WNDCLASSEXA
);
254 wc
.lpfnWndProc
= wndProc
;
257 wc
.hInstance
= GetModuleHandleA(NULL
);
258 wc
.hIcon
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
259 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
260 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
261 wc
.lpszMenuName
= NULL
;
262 wc
.lpszClassName
= wndcls
;
263 wc
.hIconSm
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
265 if (!RegisterClassExA(&wc
))
268 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
269 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
270 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
274 imc
= ImmGetContext(hwnd
);
277 win_skip("IME support not implemented\n");
280 ImmReleaseContext(hwnd
, imc
);
282 ShowWindow(hwnd
, SW_SHOWNORMAL
);
290 static void cleanup(void) {
294 UnregisterClassA(wndcls
, GetModuleHandleW(NULL
));
297 static void test_ImmNotifyIME(void) {
298 static const char string
[] = "wine";
299 char resstr
[16] = "";
303 imc
= ImmGetContext(hwnd
);
304 msg_spy_flush_msgs();
306 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
309 "Canceling an empty composition string should succeed.\n");
310 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
311 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
312 "the composition string being canceled is empty.\n");
314 ImmSetCompositionStringA(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
, 0);
315 msg_spy_flush_msgs();
317 ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
318 msg_spy_flush_msgs();
320 /* behavior differs between win9x and NT */
321 ret
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, resstr
, sizeof(resstr
));
322 ok(!ret
, "After being cancelled the composition string is empty.\n");
324 msg_spy_flush_msgs();
326 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
329 "Canceling an empty composition string should succeed.\n");
330 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
331 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
332 "the composition string being canceled is empty.\n");
334 msg_spy_flush_msgs();
335 ImmReleaseContext(hwnd
, imc
);
337 imc
= ImmCreateContext();
338 ImmDestroyContext(imc
);
340 SetLastError(0xdeadbeef);
341 ret
= ImmNotifyIME((HIMC
)0xdeadcafe, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
342 ok (ret
== 0, "Bad IME should return 0\n");
343 ret
= GetLastError();
344 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
345 SetLastError(0xdeadbeef);
346 ret
= ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
347 ok (ret
== 0, "NULL IME should return 0\n");
348 ret
= GetLastError();
349 ok(ret
== ERROR_SUCCESS
, "wrong last error %08x!\n", ret
);
350 SetLastError(0xdeadbeef);
351 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
352 ok (ret
== 0, "Destroyed IME should return 0\n");
353 ret
= GetLastError();
354 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
359 WNDPROC old_wnd_proc
;
360 BOOL catch_result_str
;
364 } ime_composition_test
;
366 static LRESULT WINAPI
test_ime_wnd_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
370 case WM_IME_COMPOSITION
:
371 if ((lParam
& GCS_RESULTSTR
) && !ime_composition_test
.catch_result_str
) {
377 ret
= CallWindowProcA(ime_composition_test
.old_wnd_proc
,
378 hWnd
, msg
, wParam
, lParam
);
380 imc
= ImmGetContext(hWnd
);
381 size
= ImmGetCompositionStringW(imc
, GCS_RESULTSTR
,
382 wstring
, sizeof(wstring
));
383 ok(size
> 0, "ImmGetCompositionString(GCS_RESULTSTR) is %d\n", size
);
384 ImmReleaseContext(hwnd
, imc
);
386 ime_composition_test
.catch_result_str
= TRUE
;
391 if (!ime_composition_test
.catch_ime_char
)
392 ime_composition_test
.catch_ime_char
= TRUE
;
395 if (wParam
== ime_composition_test
.timer_id
) {
396 HWND parent
= GetParent(hWnd
);
398 int left
= 20 - (GetTickCount() - ime_composition_test
.start
) / 1000;
399 wsprintfA(title
, "%sLeft %d sec. - IME composition test",
400 ime_composition_test
.catch_result_str
? "[*] " : "", left
);
401 SetWindowTextA(parent
, title
);
403 DestroyWindow(parent
);
405 SetTimer(hWnd
, wParam
, 100, NULL
);
410 return CallWindowProcA(ime_composition_test
.old_wnd_proc
,
411 hWnd
, msg
, wParam
, lParam
);
414 static void test_ImmGetCompositionString(void)
417 static const WCHAR string
[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
425 imc
= ImmGetContext(hwnd
);
426 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
,0);
428 win_skip("Composition isn't supported\n");
429 ImmReleaseContext(hwnd
, imc
);
432 msg_spy_flush_msgs();
434 alen
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 20);
435 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 20);
436 /* windows machines without any IME installed just return 0 above */
439 len
= ImmGetCompositionStringW(imc
, GCS_COMPATTR
, NULL
, 0);
440 ok(len
*sizeof(WCHAR
)==wlen
,"GCS_COMPATTR(W) not returning correct count\n");
441 len
= ImmGetCompositionStringA(imc
, GCS_COMPATTR
, NULL
, 0);
442 ok(len
==alen
,"GCS_COMPATTR(A) not returning correct count\n");
445 win_skip("Composition string isn't available\n");
447 ImmReleaseContext(hwnd
, imc
);
449 /* Test composition results input by IMM API */
450 prop
= ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR
);
451 if (!(prop
& SCS_CAP_COMPSTR
)) {
452 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */
453 skip("This IME doesn't support SCS_SETSTR\n");
456 ime_composition_test
.old_wnd_proc
=
457 (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
458 (LONG_PTR
)test_ime_wnd_proc
);
459 imc
= ImmGetContext(hwnd
);
460 msg_spy_flush_msgs();
462 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
,
463 string
, sizeof(string
), NULL
,0);
464 ok(ret
, "ImmSetCompositionStringW failed\n");
465 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
,
466 wstring
, sizeof(wstring
));
468 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
469 ok(ret
, "ImmNotifyIME(CPS_COMPLETE) failed\n");
470 msg_spy_flush_msgs();
471 ok(ime_composition_test
.catch_result_str
,
472 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n");
473 ok(ime_composition_test
.catch_ime_char
,
474 "WM_IME_CHAR isn't sent\n");
477 win_skip("Composition string isn't available\n");
478 ImmReleaseContext(hwnd
, imc
);
479 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
480 (LONG_PTR
)ime_composition_test
.old_wnd_proc
);
481 msg_spy_flush_msgs();
484 /* Test composition results input by hand */
485 memset(&ime_composition_test
, 0, sizeof(ime_composition_test
));
486 if (winetest_interactive
) {
487 HWND hwndMain
, hwndChild
;
489 const DWORD MY_TIMER
= 0xcaffe;
491 hwndMain
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
,
492 "IME composition test",
493 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
494 CW_USEDEFAULT
, CW_USEDEFAULT
, 320, 160,
495 NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
496 hwndChild
= CreateWindowExA(0, "static",
497 "Input a DBCS character here using IME.",
498 WS_CHILD
| WS_VISIBLE
| 0
499 /* ES_AUTOHSCROLL | ES_MULTILINE */,
500 0, 0, 320, 100, hwndMain
, NULL
,
501 GetModuleHandleA(NULL
), NULL
);
503 ime_composition_test
.old_wnd_proc
=
504 (WNDPROC
)SetWindowLongPtrA(hwndChild
, GWLP_WNDPROC
,
505 (LONG_PTR
)test_ime_wnd_proc
);
509 /* FIXME: In wine, IME UI window is created in ImmSetOpenStatus().
510 So, we prepare it here to generate WM_IME_CHAR messages. */
511 imc
= ImmGetContext(hwndChild
);
512 ImmSetOpenStatus(imc
, FALSE
);
513 ImmReleaseContext(hwndChild
, imc
);
515 ime_composition_test
.timer_id
= MY_TIMER
;
516 ime_composition_test
.start
= GetTickCount();
517 SetTimer(hwndChild
, ime_composition_test
.timer_id
, 100, NULL
);
518 while (GetMessageA(&msg
, NULL
, 0, 0)) {
519 TranslateMessage(&msg
);
520 DispatchMessageA(&msg
);
521 if (!IsWindow(hwndMain
))
524 if (!ime_composition_test
.catch_result_str
)
525 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n");
527 ok(ime_composition_test
.catch_ime_char
,
528 "WM_IME_CHAR isn't sent\n");
529 msg_spy_flush_msgs();
533 static void test_ImmSetCompositionString(void)
538 SetLastError(0xdeadbeef);
539 imc
= ImmGetContext(hwnd
);
540 ok(imc
!= 0, "ImmGetContext() failed. Last error: %u\n", GetLastError());
544 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, NULL
, 0, NULL
, 0);
547 "ImmSetCompositionStringW() failed.\n");
549 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
,
551 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
553 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGECLAUSE
,
555 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
557 ret
= ImmSetCompositionStringW(imc
, SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
559 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
561 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
563 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
565 ImmReleaseContext(hwnd
, imc
);
568 static void test_ImmIME(void)
572 imc
= ImmGetContext(hwnd
);
576 rc
= ImmConfigureIMEA(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
577 ok (rc
== 0, "ImmConfigureIMEA did not fail\n");
578 rc
= ImmConfigureIMEW(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
579 ok (rc
== 0, "ImmConfigureIMEW did not fail\n");
581 ImmReleaseContext(hwnd
,imc
);
584 static void test_ImmAssociateContextEx(void)
589 if (!pImmAssociateContextEx
) return;
591 imc
= ImmGetContext(hwnd
);
596 newimc
= ImmCreateContext();
597 ok(newimc
!= imc
, "handles should not be the same\n");
598 rc
= pImmAssociateContextEx(NULL
, NULL
, 0);
599 ok(!rc
, "ImmAssociateContextEx succeeded\n");
600 rc
= pImmAssociateContextEx(hwnd
, NULL
, 0);
601 ok(rc
, "ImmAssociateContextEx failed\n");
602 rc
= pImmAssociateContextEx(NULL
, imc
, 0);
603 ok(!rc
, "ImmAssociateContextEx succeeded\n");
605 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
606 ok(rc
, "ImmAssociateContextEx failed\n");
607 retimc
= ImmGetContext(hwnd
);
608 ok(retimc
== imc
, "handles should be the same\n");
609 ImmReleaseContext(hwnd
,retimc
);
611 rc
= pImmAssociateContextEx(hwnd
, newimc
, 0);
612 ok(rc
, "ImmAssociateContextEx failed\n");
613 retimc
= ImmGetContext(hwnd
);
614 ok(retimc
== newimc
, "handles should be the same\n");
615 ImmReleaseContext(hwnd
,retimc
);
617 rc
= pImmAssociateContextEx(hwnd
, NULL
, IACE_DEFAULT
);
618 ok(rc
, "ImmAssociateContextEx failed\n");
620 ImmReleaseContext(hwnd
,imc
);
623 typedef struct _igc_threadinfo
{
631 static DWORD WINAPI
ImmGetContextThreadFunc( LPVOID lpParam
)
640 igc_threadinfo
*info
= (igc_threadinfo
*)lpParam
;
641 info
->hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
642 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
643 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
645 h1
= ImmGetContext(hwnd
);
646 ok(info
->himc
== h1
, "hwnd context changed in new thread\n");
647 h2
= ImmGetContext(info
->hwnd
);
648 ok(h2
!= h1
, "new hwnd in new thread should have different context\n");
650 ImmReleaseContext(hwnd
,h1
);
652 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
653 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
654 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
655 h1
= ImmGetContext(hwnd2
);
657 ok(h1
== h2
, "Windows in same thread should have same default context\n");
658 ImmReleaseContext(hwnd2
,h1
);
659 ImmReleaseContext(info
->hwnd
,h2
);
660 DestroyWindow(hwnd2
);
662 /* priming for later tests */
663 ImmSetCompositionWindow(h1
, &cf
);
664 ImmSetStatusWindowPos(h1
, &pt
);
665 info
->u_himc
= ImmCreateContext();
666 ImmSetOpenStatus(info
->u_himc
, TRUE
);
668 cdf
.dwStyle
= CFS_CANDIDATEPOS
;
669 cdf
.ptCurrentPos
.x
= 0;
670 cdf
.ptCurrentPos
.y
= 0;
671 ImmSetCandidateWindow(info
->u_himc
, &cdf
);
673 SetEvent(info
->event
);
675 while(GetMessageW(&msg
, 0, 0, 0))
677 TranslateMessage(&msg
);
678 DispatchMessageW(&msg
);
683 static void test_ImmThreads(void)
685 HIMC himc
, otherHimc
, h1
;
686 igc_threadinfo threadinfo
;
693 DWORD status
, sentence
;
696 himc
= ImmGetContext(hwnd
);
697 threadinfo
.event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
698 threadinfo
.himc
= himc
;
699 hThread
= CreateThread(NULL
, 0, ImmGetContextThreadFunc
, &threadinfo
, 0, &dwThreadId
);
700 WaitForSingleObject(threadinfo
.event
, INFINITE
);
702 otherHimc
= ImmGetContext(threadinfo
.hwnd
);
704 ok(himc
!= otherHimc
, "Windows from other threads should have different himc\n");
705 ok(otherHimc
== threadinfo
.himc
, "Context from other thread should not change in main thread\n");
707 h1
= ImmAssociateContext(hwnd
,otherHimc
);
708 ok(h1
== NULL
, "Should fail to be able to Associate a default context from a different thread\n");
709 h1
= ImmGetContext(hwnd
);
710 ok(h1
== himc
, "Context for window should remain unchanged\n");
711 ImmReleaseContext(hwnd
,h1
);
713 h1
= ImmAssociateContext(hwnd
, threadinfo
.u_himc
);
714 ok (h1
== NULL
, "Should fail to associate a context from a different thread\n");
715 h1
= ImmGetContext(hwnd
);
716 ok(h1
== himc
, "Context for window should remain unchanged\n");
717 ImmReleaseContext(hwnd
,h1
);
719 h1
= ImmAssociateContext(threadinfo
.hwnd
, threadinfo
.u_himc
);
720 ok (h1
== NULL
, "Should fail to associate a context from a different thread into a window from that thread.\n");
721 h1
= ImmGetContext(threadinfo
.hwnd
);
722 ok(h1
== threadinfo
.himc
, "Context for window should remain unchanged\n");
723 ImmReleaseContext(threadinfo
.hwnd
,h1
);
726 rc
= ImmSetOpenStatus(himc
, TRUE
);
727 ok(rc
!= 0, "ImmSetOpenStatus failed\n");
728 rc
= ImmGetOpenStatus(himc
);
729 ok(rc
!= 0, "ImmGetOpenStatus failed\n");
730 rc
= ImmSetOpenStatus(himc
, FALSE
);
731 ok(rc
!= 0, "ImmSetOpenStatus failed\n");
732 rc
= ImmGetOpenStatus(himc
);
733 ok(rc
== 0, "ImmGetOpenStatus failed\n");
735 rc
= ImmSetOpenStatus(otherHimc
, TRUE
);
736 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
737 rc
= ImmSetOpenStatus(threadinfo
.u_himc
, TRUE
);
738 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
739 rc
= ImmGetOpenStatus(otherHimc
);
740 ok(rc
== 0, "ImmGetOpenStatus failed\n");
741 rc
= ImmGetOpenStatus(threadinfo
.u_himc
);
742 ok (rc
== 1 || broken(rc
== 0), "ImmGetOpenStatus should return 1\n");
743 rc
= ImmSetOpenStatus(otherHimc
, FALSE
);
744 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
745 rc
= ImmGetOpenStatus(otherHimc
);
746 ok(rc
== 0, "ImmGetOpenStatus failed\n");
748 /* CompositionFont */
749 rc
= ImmGetCompositionFontA(himc
, &lf
);
750 ok(rc
!= 0, "ImmGetCompositionFont failed\n");
751 rc
= ImmSetCompositionFontA(himc
, &lf
);
752 ok(rc
!= 0, "ImmSetCompositionFont failed\n");
754 rc
= ImmGetCompositionFontA(otherHimc
, &lf
);
755 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionFont failed\n");
756 rc
= ImmGetCompositionFontA(threadinfo
.u_himc
, &lf
);
757 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionFont user himc failed\n");
758 rc
= ImmSetCompositionFontA(otherHimc
, &lf
);
759 ok(rc
== 0, "ImmSetCompositionFont should fail\n");
760 rc
= ImmSetCompositionFontA(threadinfo
.u_himc
, &lf
);
761 ok(rc
== 0, "ImmSetCompositionFont should fail\n");
763 /* CompositionWindow */
764 rc
= ImmSetCompositionWindow(himc
, &cf
);
765 ok(rc
!= 0, "ImmSetCompositionWindow failed\n");
766 rc
= ImmGetCompositionWindow(himc
, &cf
);
767 ok(rc
!= 0, "ImmGetCompositionWindow failed\n");
769 rc
= ImmSetCompositionWindow(otherHimc
, &cf
);
770 ok(rc
== 0, "ImmSetCompositionWindow should fail\n");
771 rc
= ImmSetCompositionWindow(threadinfo
.u_himc
, &cf
);
772 ok(rc
== 0, "ImmSetCompositionWindow should fail\n");
773 rc
= ImmGetCompositionWindow(otherHimc
, &cf
);
774 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionWindow failed\n");
775 rc
= ImmGetCompositionWindow(threadinfo
.u_himc
, &cf
);
776 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionWindow failed\n");
778 /* ConversionStatus */
779 rc
= ImmGetConversionStatus(himc
, &status
, &sentence
);
780 ok(rc
!= 0, "ImmGetConversionStatus failed\n");
781 rc
= ImmSetConversionStatus(himc
, status
, sentence
);
782 ok(rc
!= 0, "ImmSetConversionStatus failed\n");
784 rc
= ImmGetConversionStatus(otherHimc
, &status
, &sentence
);
785 ok(rc
!= 0 || broken(rc
== 0), "ImmGetConversionStatus failed\n");
786 rc
= ImmGetConversionStatus(threadinfo
.u_himc
, &status
, &sentence
);
787 ok(rc
!= 0 || broken(rc
== 0), "ImmGetConversionStatus failed\n");
788 rc
= ImmSetConversionStatus(otherHimc
, status
, sentence
);
789 ok(rc
== 0, "ImmSetConversionStatus should fail\n");
790 rc
= ImmSetConversionStatus(threadinfo
.u_himc
, status
, sentence
);
791 ok(rc
== 0, "ImmSetConversionStatus should fail\n");
793 /* StatusWindowPos */
794 rc
= ImmSetStatusWindowPos(himc
, &pt
);
795 ok(rc
!= 0, "ImmSetStatusWindowPos failed\n");
796 rc
= ImmGetStatusWindowPos(himc
, &pt
);
797 ok(rc
!= 0, "ImmGetStatusWindowPos failed\n");
799 rc
= ImmSetStatusWindowPos(otherHimc
, &pt
);
800 ok(rc
== 0, "ImmSetStatusWindowPos should fail\n");
801 rc
= ImmSetStatusWindowPos(threadinfo
.u_himc
, &pt
);
802 ok(rc
== 0, "ImmSetStatusWindowPos should fail\n");
803 rc
= ImmGetStatusWindowPos(otherHimc
, &pt
);
804 ok(rc
!= 0 || broken(rc
== 0), "ImmGetStatusWindowPos failed\n");
805 rc
= ImmGetStatusWindowPos(threadinfo
.u_himc
, &pt
);
806 ok(rc
!= 0 || broken(rc
== 0), "ImmGetStatusWindowPos failed\n");
808 h1
= ImmAssociateContext(threadinfo
.hwnd
, NULL
);
809 ok (h1
== otherHimc
, "ImmAssociateContext cross thread with NULL should work\n");
810 h1
= ImmGetContext(threadinfo
.hwnd
);
811 ok (h1
== NULL
, "CrossThread window context should be NULL\n");
812 h1
= ImmAssociateContext(threadinfo
.hwnd
, h1
);
813 ok (h1
== NULL
, "Resetting cross thread context should fail\n");
814 h1
= ImmGetContext(threadinfo
.hwnd
);
815 ok (h1
== NULL
, "CrossThread window context should still be NULL\n");
817 rc
= ImmDestroyContext(threadinfo
.u_himc
);
818 ok (rc
== 0, "ImmDestroyContext Cross Thread should fail\n");
820 /* Candidate Window */
821 rc
= ImmGetCandidateWindow(himc
, 0, &cdf
);
822 ok (rc
== 0, "ImmGetCandidateWindow should fail\n");
824 cdf
.dwStyle
= CFS_CANDIDATEPOS
;
825 cdf
.ptCurrentPos
.x
= 0;
826 cdf
.ptCurrentPos
.y
= 0;
827 rc
= ImmSetCandidateWindow(himc
, &cdf
);
828 ok (rc
== 1, "ImmSetCandidateWindow should succeed\n");
829 rc
= ImmGetCandidateWindow(himc
, 0, &cdf
);
830 ok (rc
== 1, "ImmGetCandidateWindow should succeed\n");
832 rc
= ImmGetCandidateWindow(otherHimc
, 0, &cdf
);
833 ok (rc
== 0, "ImmGetCandidateWindow should fail\n");
834 rc
= ImmSetCandidateWindow(otherHimc
, &cdf
);
835 ok (rc
== 0, "ImmSetCandidateWindow should fail\n");
836 rc
= ImmGetCandidateWindow(threadinfo
.u_himc
, 0, &cdf
);
837 ok (rc
== 1 || broken( rc
== 0), "ImmGetCandidateWindow should succeed\n");
838 rc
= ImmSetCandidateWindow(threadinfo
.u_himc
, &cdf
);
839 ok (rc
== 0, "ImmSetCandidateWindow should fail\n");
841 ImmReleaseContext(threadinfo
.hwnd
,otherHimc
);
842 ImmReleaseContext(hwnd
,himc
);
844 SendMessageA(threadinfo
.hwnd
, WM_CLOSE
, 0, 0);
845 rc
= PostThreadMessageA(dwThreadId
, WM_QUIT
, 1, 0);
846 ok(rc
== 1, "PostThreadMessage should succeed\n");
847 WaitForSingleObject(hThread
, INFINITE
);
848 CloseHandle(hThread
);
850 himc
= ImmGetContext(GetDesktopWindow());
851 ok(himc
== NULL
, "Should not be able to get himc from other process window\n");
854 static void test_ImmIsUIMessage(void)
862 static const struct test tests
[] =
864 { WM_MOUSEMOVE
, FALSE
},
865 { WM_IME_STARTCOMPOSITION
, TRUE
},
866 { WM_IME_ENDCOMPOSITION
, TRUE
},
867 { WM_IME_COMPOSITION
, TRUE
},
868 { WM_IME_SETCONTEXT
, TRUE
},
869 { WM_IME_NOTIFY
, TRUE
},
870 { WM_IME_CONTROL
, FALSE
},
871 { WM_IME_COMPOSITIONFULL
, TRUE
},
872 { WM_IME_SELECT
, TRUE
},
873 { WM_IME_CHAR
, FALSE
},
874 { 0x287 /* FIXME */, TRUE
},
875 { WM_IME_REQUEST
, FALSE
},
876 { WM_IME_KEYDOWN
, FALSE
},
877 { WM_IME_KEYUP
, FALSE
},
878 { 0, FALSE
} /* mark the end */
881 UINT WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
882 UINT WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
883 UINT WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
884 UINT WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
885 UINT WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
886 UINT WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
887 UINT WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
889 const struct test
*test
;
892 if (!pImmIsUIMessageA
) return;
894 for (test
= tests
; test
->msg
; test
++)
896 msg_spy_flush_msgs();
897 ret
= pImmIsUIMessageA(NULL
, test
->msg
, 0, 0);
898 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
899 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x for NULL hwnd\n", test
->msg
);
901 ret
= pImmIsUIMessageA(hwnd
, test
->msg
, 0, 0);
902 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
904 ok(msg_spy_find_msg(test
->msg
) != NULL
, "Windows does send 0x%x\n", test
->msg
);
906 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x\n", test
->msg
);
909 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_SERVICE
, 0, 0);
910 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n");
911 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTOPTIONS
, 0, 0);
912 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n");
913 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_MOUSE
, 0, 0);
914 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n");
915 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTREQUEST
, 0, 0);
916 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n");
917 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERT
, 0, 0);
918 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n");
919 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_QUERYPOSITION
, 0, 0);
920 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n");
921 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_DOCUMENTFEED
, 0, 0);
922 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n");
925 static void test_ImmGetContext(void)
930 SetLastError(0xdeadbeef);
931 himc
= ImmGetContext((HWND
)0xffffffff);
932 err
= GetLastError();
933 ok(himc
== NULL
, "ImmGetContext succeeded\n");
934 ok(err
== ERROR_INVALID_WINDOW_HANDLE
, "got %u\n", err
);
936 himc
= ImmGetContext(hwnd
);
937 ok(himc
!= NULL
, "ImmGetContext failed\n");
938 ok(ImmReleaseContext(hwnd
, himc
), "ImmReleaseContext failed\n");
941 static void test_ImmGetDescription(void)
948 /* FIXME: invalid keyboard layouts should not pass */
949 ret
= ImmGetDescriptionW(NULL
, NULL
, 0);
950 ok(!ret
, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret
);
951 ret
= ImmGetDescriptionA(NULL
, NULL
, 0);
952 ok(!ret
, "ImmGetDescriptionA failed, expected 0 received %d.\n", ret
);
954 /* load a language with valid IMM descriptions */
955 hkl
= GetKeyboardLayout(0);
956 ok(hkl
!= 0, "GetKeyboardLayout failed, expected != 0.\n");
958 ret
= ImmGetDescriptionW(hkl
, NULL
, 0);
961 win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n");
965 SetLastError(0xdeadcafe);
966 ret
= ImmGetDescriptionW(0, NULL
, 100);
967 ok (ret
== 0, "ImmGetDescriptionW with 0 hkl should return 0\n");
968 ret
= GetLastError();
969 ok (ret
== 0xdeadcafe, "Last Error should remain unchanged\n");
971 ret
= ImmGetDescriptionW(hkl
, descW
, 0);
972 ok(ret
, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
974 lret
= ImmGetDescriptionW(hkl
, descW
, ret
+ 1);
975 ok(lret
, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
976 ok(lret
== ret
, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret
, lret
);
978 lret
= ImmGetDescriptionA(hkl
, descA
, ret
+ 1);
979 ok(lret
, "ImmGetDescriptionA failed, expected != 0 received 0.\n");
980 ok(lret
== ret
, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret
, lret
);
982 ret
/= 2; /* try to copy partially */
983 lret
= ImmGetDescriptionW(hkl
, descW
, ret
+ 1);
984 ok(lret
, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
985 ok(lret
== ret
, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret
, lret
);
987 lret
= ImmGetDescriptionA(hkl
, descA
, ret
+ 1);
988 ok(!lret
, "ImmGetDescriptionA should fail\n");
990 ret
= ImmGetDescriptionW(hkl
, descW
, 1);
991 ok(!ret
, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret
);
993 UnloadKeyboardLayout(hkl
);
996 static LRESULT (WINAPI
*old_imm_wnd_proc
)(HWND
, UINT
, WPARAM
, LPARAM
);
997 static LRESULT WINAPI
imm_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
999 ok(msg
!= WM_DESTROY
, "got WM_DESTROY message\n");
1000 return old_imm_wnd_proc(hwnd
, msg
, wparam
, lparam
);
1003 static HWND thread_ime_wnd
;
1004 static DWORD WINAPI
test_ImmGetDefaultIMEWnd_thread(void *arg
)
1006 CreateWindowA("static", "static", WS_POPUP
, 0, 0, 1, 1, NULL
, NULL
, NULL
, NULL
);
1008 thread_ime_wnd
= ImmGetDefaultIMEWnd(0);
1009 ok(thread_ime_wnd
!= 0, "ImmGetDefaultIMEWnd returned NULL\n");
1010 old_imm_wnd_proc
= (void*)SetWindowLongPtrW(thread_ime_wnd
, GWLP_WNDPROC
, (LONG_PTR
)imm_wnd_proc
);
1014 static void test_ImmDefaultHwnd(void)
1016 HIMC imc1
, imc2
, imc3
;
1023 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1024 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1025 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1027 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1029 imc1
= ImmGetContext(hwnd
);
1032 win_skip("IME support not implemented\n");
1036 def1
= ImmGetDefaultIMEWnd(hwnd
);
1038 GetWindowTextA(def1
, title
, sizeof(title
));
1039 ok(!strcmp(title
, "Default IME"), "got %s\n", title
);
1040 style
= GetWindowLongA(def1
, GWL_STYLE
);
1041 ok(style
== (WS_DISABLED
| WS_POPUP
| WS_CLIPSIBLINGS
), "got %08x\n", style
);
1042 style
= GetWindowLongA(def1
, GWL_EXSTYLE
);
1043 ok(style
== 0, "got %08x\n", style
);
1045 imc2
= ImmCreateContext();
1046 ImmSetOpenStatus(imc2
, TRUE
);
1048 imc3
= ImmGetContext(hwnd
);
1049 def3
= ImmGetDefaultIMEWnd(hwnd
);
1051 ok(def3
== def1
, "Default IME window should not change\n");
1052 ok(imc1
== imc3
, "IME context should not change\n");
1053 ImmSetOpenStatus(imc2
, FALSE
);
1055 thread
= CreateThread(NULL
, 0, test_ImmGetDefaultIMEWnd_thread
, NULL
, 0, NULL
);
1056 WaitForSingleObject(thread
, INFINITE
);
1057 ok(thread_ime_wnd
!= def1
, "thread_ime_wnd == def1\n");
1058 ok(!IsWindow(thread_ime_wnd
), "thread_ime_wnd was not destroyed\n");
1059 CloseHandle(thread
);
1061 ImmReleaseContext(hwnd
, imc1
);
1062 ImmReleaseContext(hwnd
, imc3
);
1063 ImmDestroyContext(imc2
);
1064 DestroyWindow(hwnd
);
1067 static BOOL CALLBACK
is_ime_window_proc(HWND hWnd
, LPARAM param
)
1069 static const WCHAR imeW
[] = {'I','M','E',0};
1070 WCHAR class_nameW
[16];
1071 HWND
*ime_window
= (HWND
*)param
;
1072 if (GetClassNameW(hWnd
, class_nameW
, sizeof(class_nameW
)/sizeof(class_nameW
[0])) &&
1073 !lstrcmpW(class_nameW
, imeW
)) {
1080 static HWND
get_ime_window(void)
1082 HWND ime_window
= NULL
;
1083 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc
, (LPARAM
)&ime_window
);
1087 struct testcase_ime_window
{
1089 BOOL top_level_window
;
1092 static DWORD WINAPI
test_default_ime_window_cb(void *arg
)
1094 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1095 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1096 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
1098 ok(!get_ime_window(), "Expected no IME windows\n");
1099 if (testcase
->top_level_window
) {
1100 test_phase
= FIRST_WINDOW
;
1101 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1102 WS_OVERLAPPEDWINDOW
| visible
,
1103 CW_USEDEFAULT
, CW_USEDEFAULT
,
1104 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1107 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1109 CW_USEDEFAULT
, CW_USEDEFAULT
,
1110 240, 24, hwnd
, NULL
, GetModuleHandleW(NULL
), NULL
);
1112 ime_wnd
= get_ime_window();
1113 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
1114 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1115 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
1117 test_phase
= SECOND_WINDOW
;
1118 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1119 WS_OVERLAPPEDWINDOW
| visible
,
1120 CW_USEDEFAULT
, CW_USEDEFAULT
,
1121 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1122 DestroyWindow(hwnd2
);
1123 ok(IsWindow(ime_wnd
) ||
1124 broken(!testcase
->visible
/* Vista */) ||
1125 broken(!testcase
->top_level_window
/* Vista */) ,
1126 "Expected IME window existence\n");
1127 DestroyWindow(hwnd1
);
1128 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
1132 static DWORD WINAPI
test_default_ime_window_cancel_cb(void *arg
)
1134 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1135 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1136 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
1138 ok(!get_ime_window(), "Expected no IME windows\n");
1139 test_phase
= NCCREATE_CANCEL
;
1140 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1141 WS_OVERLAPPEDWINDOW
| visible
,
1142 CW_USEDEFAULT
, CW_USEDEFAULT
,
1143 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1144 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
1145 ok(!get_ime_window(), "Expected no IME windows\n");
1147 test_phase
= CREATE_CANCEL
;
1148 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1149 WS_OVERLAPPEDWINDOW
| visible
,
1150 CW_USEDEFAULT
, CW_USEDEFAULT
,
1151 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1152 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
1153 ok(!get_ime_window(), "Expected no IME windows\n");
1155 test_phase
= FIRST_WINDOW
;
1156 hwnd2
= 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 ime_wnd
= get_ime_window();
1161 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
1162 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
1163 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
1165 DestroyWindow(hwnd2
);
1166 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
1170 static DWORD WINAPI
test_default_ime_disabled_cb(void *arg
)
1172 HWND hWnd
, default_ime_wnd
;
1174 ok(!get_ime_window(), "Expected no IME windows\n");
1175 ImmDisableIME(GetCurrentThreadId());
1176 test_phase
= IME_DISABLED
;
1177 hWnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1178 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1179 CW_USEDEFAULT
, CW_USEDEFAULT
,
1180 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1181 default_ime_wnd
= ImmGetDefaultIMEWnd(hWnd
);
1182 ok(!default_ime_wnd
, "Expected no IME windows\n");
1183 DestroyWindow(hWnd
);
1187 static DWORD WINAPI
test_default_ime_with_message_only_window_cb(void *arg
)
1189 HWND hwnd1
, hwnd2
, default_ime_wnd
;
1191 test_phase
= PHASE_UNKNOWN
;
1192 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1193 WS_OVERLAPPEDWINDOW
,
1194 CW_USEDEFAULT
, CW_USEDEFAULT
,
1195 240, 120, HWND_MESSAGE
, NULL
, GetModuleHandleW(NULL
), NULL
);
1196 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1197 ok(!IsWindow(default_ime_wnd
), "Expected no IME windows, got %p\n", default_ime_wnd
);
1199 hwnd2
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1200 WS_OVERLAPPEDWINDOW
,
1201 CW_USEDEFAULT
, CW_USEDEFAULT
,
1202 240, 120, hwnd1
, NULL
, GetModuleHandleW(NULL
), NULL
);
1203 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
1204 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1206 DestroyWindow(hwnd2
);
1207 DestroyWindow(hwnd1
);
1209 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1210 WS_OVERLAPPEDWINDOW
,
1211 CW_USEDEFAULT
, CW_USEDEFAULT
,
1212 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1213 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1214 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1215 SetParent(hwnd1
, HWND_MESSAGE
);
1216 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1217 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1218 DestroyWindow(hwnd1
);
1222 static void test_default_ime_window_creation(void)
1226 struct testcase_ime_window testcases
[] = {
1227 /* visible, top-level window */
1234 for (i
= 0; i
< sizeof(testcases
)/sizeof(testcases
[0]); i
++)
1236 thread
= CreateThread(NULL
, 0, test_default_ime_window_cb
, &testcases
[i
], 0, NULL
);
1237 ok(thread
!= NULL
, "CreateThread failed with error %u\n", GetLastError());
1238 while (MsgWaitForMultipleObjects(1, &thread
, FALSE
, INFINITE
, QS_ALLINPUT
) == WAIT_OBJECT_0
+ 1)
1241 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
1243 TranslateMessage(&msg
);
1244 DispatchMessageA(&msg
);
1247 CloseHandle(thread
);
1249 if (testcases
[i
].top_level_window
)
1251 thread
= CreateThread(NULL
, 0, test_default_ime_window_cancel_cb
, &testcases
[i
], 0, NULL
);
1252 ok(thread
!= NULL
, "CreateThread failed with error %u\n", GetLastError());
1253 WaitForSingleObject(thread
, INFINITE
);
1254 CloseHandle(thread
);
1258 thread
= CreateThread(NULL
, 0, test_default_ime_disabled_cb
, NULL
, 0, NULL
);
1259 WaitForSingleObject(thread
, INFINITE
);
1260 CloseHandle(thread
);
1262 thread
= CreateThread(NULL
, 0, test_default_ime_with_message_only_window_cb
, NULL
, 0, NULL
);
1263 WaitForSingleObject(thread
, INFINITE
);
1264 CloseHandle(thread
);
1266 test_phase
= PHASE_UNKNOWN
;
1269 static void test_ImmGetIMCLockCount(void)
1272 DWORD count
, ret
, i
;
1275 imc
= ImmCreateContext();
1276 ImmDestroyContext(imc
);
1277 SetLastError(0xdeadbeef);
1278 count
= ImmGetIMCLockCount((HIMC
)0xdeadcafe);
1279 ok(count
== 0, "Invalid IMC should return 0\n");
1280 ret
= GetLastError();
1281 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1282 SetLastError(0xdeadbeef);
1283 count
= ImmGetIMCLockCount(0x00000000);
1284 ok(count
== 0, "NULL IMC should return 0\n");
1285 ret
= GetLastError();
1286 ok(ret
== 0xdeadbeef, "Last Error should remain unchanged: %08x\n",ret
);
1287 count
= ImmGetIMCLockCount(imc
);
1288 ok(count
== 0, "Destroyed IMC should return 0\n");
1289 ret
= GetLastError();
1290 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1292 imc
= ImmCreateContext();
1293 count
= ImmGetIMCLockCount(imc
);
1294 ok(count
== 0, "expect 0, returned %d\n", count
);
1295 ic
= ImmLockIMC(imc
);
1296 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1297 count
= ImmGetIMCLockCount(imc
);
1298 ok(count
== 1, "expect 1, returned %d\n", count
);
1299 ret
= ImmUnlockIMC(imc
);
1300 ok(ret
== TRUE
, "expect TRUE, ret %d\n", ret
);
1301 count
= ImmGetIMCLockCount(imc
);
1302 ok(count
== 0, "expect 0, returned %d\n", count
);
1303 ret
= ImmUnlockIMC(imc
);
1304 ok(ret
== TRUE
, "expect TRUE, ret %d\n", ret
);
1305 count
= ImmGetIMCLockCount(imc
);
1306 ok(count
== 0, "expect 0, returned %d\n", count
);
1308 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
1310 ic
= ImmLockIMC(imc
);
1311 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1313 count
= ImmGetIMCLockCount(imc
);
1314 todo_wine
ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %d\n", count
);
1316 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
1318 count
= ImmGetIMCLockCount(imc
);
1319 todo_wine
ok(count
== 1, "expect 1, returned %d\n", count
);
1321 count
= ImmGetIMCLockCount(imc
);
1322 todo_wine
ok(count
== 0, "expect 0, returned %d\n", count
);
1324 ImmDestroyContext(imc
);
1327 static void test_ImmGetIMCCLockCount(void)
1330 DWORD count
, g_count
, i
;
1334 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
1335 count
= ImmGetIMCCLockCount(imcc
);
1336 ok(count
== 0, "expect 0, returned %d\n", count
);
1338 count
= ImmGetIMCCLockCount(imcc
);
1339 ok(count
== 1, "expect 1, returned %d\n", count
);
1340 ret
= ImmUnlockIMCC(imcc
);
1341 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
1342 count
= ImmGetIMCCLockCount(imcc
);
1343 ok(count
== 0, "expect 0, returned %d\n", count
);
1344 ret
= ImmUnlockIMCC(imcc
);
1345 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
1346 count
= ImmGetIMCCLockCount(imcc
);
1347 ok(count
== 0, "expect 0, returned %d\n", count
);
1349 p
= ImmLockIMCC(imcc
);
1350 ok(GlobalHandle(p
) == imcc
, "expect %p, returned %p\n", imcc
, GlobalHandle(p
));
1352 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
1355 count
= ImmGetIMCCLockCount(imcc
);
1356 g_count
= GlobalFlags(imcc
) & GMEM_LOCKCOUNT
;
1357 ok(count
== g_count
, "count %d, g_count %d\n", count
, g_count
);
1359 count
= ImmGetIMCCLockCount(imcc
);
1360 ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %d\n", count
);
1362 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
1364 count
= ImmGetIMCCLockCount(imcc
);
1365 ok(count
== 1, "expect 1, returned %d\n", count
);
1367 count
= ImmGetIMCCLockCount(imcc
);
1368 ok(count
== 0, "expect 0, returned %d\n", count
);
1370 ImmDestroyIMCC(imcc
);
1373 static void test_ImmDestroyContext(void)
1379 imc
= ImmCreateContext();
1380 count
= ImmGetIMCLockCount(imc
);
1381 ok(count
== 0, "expect 0, returned %d\n", count
);
1382 ic
= ImmLockIMC(imc
);
1383 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1384 count
= ImmGetIMCLockCount(imc
);
1385 ok(count
== 1, "expect 1, returned %d\n", count
);
1386 ret
= ImmDestroyContext(imc
);
1387 ok(ret
== TRUE
, "Destroy a locked IMC should success!\n");
1388 ic
= ImmLockIMC(imc
);
1389 ok(ic
== NULL
, "Lock a destroyed IMC should fail!\n");
1390 ret
= ImmUnlockIMC(imc
);
1391 ok(ret
== FALSE
, "Unlock a destroyed IMC should fail!\n");
1392 count
= ImmGetIMCLockCount(imc
);
1393 ok(count
== 0, "Get lock count of a destroyed IMC should return 0!\n");
1394 SetLastError(0xdeadbeef);
1395 ret
= ImmDestroyContext(imc
);
1396 ok(ret
== FALSE
, "Destroy a destroyed IMC should fail!\n");
1397 ret
= GetLastError();
1398 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1401 static void test_ImmDestroyIMCC(void)
1404 DWORD ret
, count
, size
;
1407 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
1408 count
= ImmGetIMCCLockCount(imcc
);
1409 ok(count
== 0, "expect 0, returned %d\n", count
);
1410 p
= ImmLockIMCC(imcc
);
1411 ok(p
!= NULL
, "ImmLockIMCC failed!\n");
1412 count
= ImmGetIMCCLockCount(imcc
);
1413 ok(count
== 1, "expect 1, returned %d\n", count
);
1414 size
= ImmGetIMCCSize(imcc
);
1415 ok(size
== sizeof(CANDIDATEINFO
), "returned %d\n", size
);
1416 p
= ImmDestroyIMCC(imcc
);
1417 ok(p
== NULL
, "Destroy a locked IMCC should success!\n");
1418 p
= ImmLockIMCC(imcc
);
1419 ok(p
== NULL
, "Lock a destroyed IMCC should fail!\n");
1420 ret
= ImmUnlockIMCC(imcc
);
1421 ok(ret
== FALSE
, "Unlock a destroyed IMCC should return FALSE!\n");
1422 count
= ImmGetIMCCLockCount(imcc
);
1423 ok(count
== 0, "Get lock count of a destroyed IMCC should return 0!\n");
1424 size
= ImmGetIMCCSize(imcc
);
1425 ok(size
== 0, "Get size of a destroyed IMCC should return 0!\n");
1426 SetLastError(0xdeadbeef);
1427 p
= ImmDestroyIMCC(imcc
);
1428 ok(p
!= NULL
, "returned NULL\n");
1429 ret
= GetLastError();
1430 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1433 static void test_ImmMessages(void)
1441 LPINPUTCONTEXT lpIMC
;
1442 LPTRANSMSG lpTransMsg
;
1444 HWND hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1445 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1446 240, 120, NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
1448 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1449 defwnd
= ImmGetDefaultIMEWnd(hwnd
);
1450 imc
= ImmGetContext(hwnd
);
1452 ImmSetOpenStatus(imc
, TRUE
);
1453 msg_spy_flush_msgs();
1454 SendMessageA(defwnd
, WM_IME_CONTROL
, IMC_GETCANDIDATEPOS
, (LPARAM
)&cf
);
1457 msg
= msg_spy_find_next_msg(WM_IME_CONTROL
,&idx
);
1458 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1460 msg_spy_flush_msgs();
1462 lpIMC
= ImmLockIMC(imc
);
1463 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1464 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1465 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1466 lpTransMsg
->message
= WM_IME_STARTCOMPOSITION
;
1467 lpTransMsg
->wParam
= 0;
1468 lpTransMsg
->lParam
= 0;
1469 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1470 lpIMC
->dwNumMsgBuf
++;
1472 ImmGenerateMessage(imc
);
1476 msg
= msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION
, &idx
);
1477 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1479 msg_spy_flush_msgs();
1481 lpIMC
= ImmLockIMC(imc
);
1482 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1483 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1484 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1485 lpTransMsg
->message
= WM_IME_COMPOSITION
;
1486 lpTransMsg
->wParam
= 0;
1487 lpTransMsg
->lParam
= 0;
1488 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1489 lpIMC
->dwNumMsgBuf
++;
1491 ImmGenerateMessage(imc
);
1495 msg
= msg_spy_find_next_msg(WM_IME_COMPOSITION
, &idx
);
1496 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1498 msg_spy_flush_msgs();
1500 lpIMC
= ImmLockIMC(imc
);
1501 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1502 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1503 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1504 lpTransMsg
->message
= WM_IME_ENDCOMPOSITION
;
1505 lpTransMsg
->wParam
= 0;
1506 lpTransMsg
->lParam
= 0;
1507 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1508 lpIMC
->dwNumMsgBuf
++;
1510 ImmGenerateMessage(imc
);
1514 msg
= msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION
, &idx
);
1515 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1517 msg_spy_flush_msgs();
1519 ImmSetOpenStatus(imc
, FALSE
);
1520 ImmReleaseContext(hwnd
, imc
);
1521 DestroyWindow(hwnd
);
1524 static LRESULT CALLBACK
processkey_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
1527 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1530 static void test_ime_processkey(void)
1532 WCHAR classNameW
[] = {'P','r','o','c','e','s','s', 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1533 WCHAR windowNameW
[] = {'P','r','o','c','e','s','s', 'K','e','y',0};
1537 HANDLE hInstance
= GetModuleHandleW(NULL
);
1538 TEST_INPUT inputs
[2];
1543 wclass
.lpszClassName
= classNameW
;
1544 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1545 wclass
.lpfnWndProc
= processkey_wnd_proc
;
1546 wclass
.hInstance
= hInstance
;
1547 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
1548 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
1549 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1550 wclass
.lpszMenuName
= 0;
1551 wclass
.cbClsExtra
= 0;
1552 wclass
.cbWndExtra
= 0;
1553 if(!RegisterClassW(&wclass
)){
1554 win_skip("Failed to register window.\n");
1558 /* create the test window that will receive the keystrokes */
1559 hWndTest
= CreateWindowW(wclass
.lpszClassName
, windowNameW
,
1560 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
1561 NULL
, NULL
, hInstance
, NULL
);
1563 ShowWindow(hWndTest
, SW_SHOW
);
1564 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
1565 SetForegroundWindow(hWndTest
);
1566 UpdateWindow(hWndTest
);
1568 imc
= ImmGetContext(hWndTest
);
1571 win_skip("IME not supported\n");
1572 DestroyWindow(hWndTest
);
1576 rc
= ImmSetOpenStatus(imc
, TRUE
);
1579 win_skip("Unable to open IME\n");
1580 ImmReleaseContext(hWndTest
, imc
);
1581 DestroyWindow(hWndTest
);
1585 /* flush pending messages */
1586 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
1590 /* init input data that never changes */
1591 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
1592 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
1593 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
1595 /* Pressing a key */
1596 inputs
[0].u
.ki
.wVk
= 0x41;
1597 inputs
[0].u
.ki
.wScan
= 0x1e;
1598 inputs
[0].u
.ki
.dwFlags
= 0x0;
1600 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1602 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
1603 if(msg
.message
!= WM_KEYDOWN
)
1604 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1607 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
1608 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1609 if(msg
.wParam
== VK_PROCESSKEY
)
1610 trace("ProcessKey was correctly found\n");
1612 TranslateMessage(&msg
);
1613 DispatchMessageW(&msg
);
1616 inputs
[0].u
.ki
.wVk
= 0x41;
1617 inputs
[0].u
.ki
.wScan
= 0x1e;
1618 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1620 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1622 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
1623 if(msg
.message
!= WM_KEYUP
)
1624 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1627 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
1628 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1629 ok(msg
.wParam
!= VK_PROCESSKEY
,"ProcessKey should still not be Found\n");
1631 TranslateMessage(&msg
);
1632 DispatchMessageW(&msg
);
1635 ImmReleaseContext(hWndTest
, imc
);
1636 ImmSetOpenStatus(imc
, FALSE
);
1637 DestroyWindow(hWndTest
);
1640 static void test_InvalidIMC(void)
1643 HIMC imc_null
= 0x00000000;
1644 HIMC imc_bad
= (HIMC
)0xdeadcafe;
1646 HIMC imc1
, imc2
, oldimc
;
1653 memset(&lf
, 0, sizeof(lf
));
1655 imc_destroy
= ImmCreateContext();
1656 ret
= ImmDestroyContext(imc_destroy
);
1657 ok(ret
== TRUE
, "Destroy an IMC should success!\n");
1659 /* Test associating destroyed imc */
1660 imc1
= ImmGetContext(hwnd
);
1661 SetLastError(0xdeadbeef);
1662 oldimc
= ImmAssociateContext(hwnd
, imc_destroy
);
1663 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
1664 ret
= GetLastError();
1665 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1666 imc2
= ImmGetContext(hwnd
);
1667 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
1669 /* Test associating NULL imc, which is different from an invalid imc */
1670 oldimc
= ImmAssociateContext(hwnd
, imc_null
);
1671 ok(oldimc
!= NULL
, "Associating to NULL imc should success!\n");
1672 imc2
= ImmGetContext(hwnd
);
1673 ok(!imc2
, "expect NULL, returned %p\n", imc2
);
1674 oldimc
= ImmAssociateContext(hwnd
, imc1
);
1675 ok(!oldimc
, "expect NULL, returned %p\n", oldimc
);
1676 imc2
= ImmGetContext(hwnd
);
1677 ok(imc2
== imc1
, "imc should not changed! imc2 %p, imc1 %p\n", imc2
, imc1
);
1679 /* Test associating invalid imc */
1680 imc1
= ImmGetContext(hwnd
);
1681 SetLastError(0xdeadbeef);
1682 oldimc
= ImmAssociateContext(hwnd
, imc_bad
);
1683 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
1684 ret
= GetLastError();
1685 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1686 imc2
= ImmGetContext(hwnd
);
1687 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
1690 /* Test ImmGetCandidateListA */
1691 SetLastError(0xdeadbeef);
1692 ret
= ImmGetCandidateListA(imc_bad
, 0, NULL
, 0);
1693 ok(ret
== 0, "Bad IME should return 0\n");
1694 ret
= GetLastError();
1695 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1696 SetLastError(0xdeadbeef);
1697 ret
= ImmGetCandidateListA(imc_null
, 0, NULL
, 0);
1698 ok(ret
== 0, "NULL IME should return 0\n");
1699 ret
= GetLastError();
1700 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1701 SetLastError(0xdeadbeef);
1702 ret
= ImmGetCandidateListA(imc_destroy
, 0, NULL
, 0);
1703 ok(ret
== 0, "Destroyed IME should return 0\n");
1704 ret
= GetLastError();
1705 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1707 /* Test ImmGetCandidateListCountA*/
1708 SetLastError(0xdeadbeef);
1709 ret
= ImmGetCandidateListCountA(imc_bad
,&count
);
1710 ok(ret
== 0, "Bad IME should return 0\n");
1711 ret
= GetLastError();
1712 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1713 SetLastError(0xdeadbeef);
1714 ret
= ImmGetCandidateListCountA(imc_null
,&count
);
1715 ok(ret
== 0, "NULL IME should return 0\n");
1716 ret
= GetLastError();
1717 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1718 SetLastError(0xdeadbeef);
1719 ret
= ImmGetCandidateListCountA(imc_destroy
,&count
);
1720 ok(ret
== 0, "Destroyed IME should return 0\n");
1721 ret
= GetLastError();
1722 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1724 /* Test ImmGetCandidateWindow */
1725 SetLastError(0xdeadbeef);
1726 ret
= ImmGetCandidateWindow(imc_bad
, 0, (LPCANDIDATEFORM
)buffer
);
1727 ok(ret
== 0, "Bad IME should return 0\n");
1728 ret
= GetLastError();
1729 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1730 SetLastError(0xdeadbeef);
1731 ret
= ImmGetCandidateWindow(imc_null
, 0, (LPCANDIDATEFORM
)buffer
);
1732 ok(ret
== 0, "NULL IME should return 0\n");
1733 ret
= GetLastError();
1734 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1735 SetLastError(0xdeadbeef);
1736 ret
= ImmGetCandidateWindow(imc_destroy
, 0, (LPCANDIDATEFORM
)buffer
);
1737 ok(ret
== 0, "Destroyed IME should return 0\n");
1738 ret
= GetLastError();
1739 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1741 /* Test ImmGetCompositionFontA */
1742 SetLastError(0xdeadbeef);
1743 ret
= ImmGetCompositionFontA(imc_bad
, (LPLOGFONTA
)buffer
);
1744 ok(ret
== 0, "Bad IME should return 0\n");
1745 ret
= GetLastError();
1746 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1747 SetLastError(0xdeadbeef);
1748 ret
= ImmGetCompositionFontA(imc_null
, (LPLOGFONTA
)buffer
);
1749 ok(ret
== 0, "NULL IME should return 0\n");
1750 ret
= GetLastError();
1751 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1752 SetLastError(0xdeadbeef);
1753 ret
= ImmGetCompositionFontA(imc_destroy
, (LPLOGFONTA
)buffer
);
1754 ok(ret
== 0, "Destroyed IME should return 0\n");
1755 ret
= GetLastError();
1756 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1758 /* Test ImmGetCompositionWindow */
1759 SetLastError(0xdeadbeef);
1760 ret
= ImmGetCompositionWindow(imc_bad
, (LPCOMPOSITIONFORM
)buffer
);
1761 ok(ret
== 0, "Bad IME should return 0\n");
1762 ret
= GetLastError();
1763 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1764 SetLastError(0xdeadbeef);
1765 ret
= ImmGetCompositionWindow(imc_null
, (LPCOMPOSITIONFORM
)buffer
);
1766 ok(ret
== 0, "NULL IME should return 0\n");
1767 ret
= GetLastError();
1768 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1769 SetLastError(0xdeadbeef);
1770 ret
= ImmGetCompositionWindow(imc_destroy
, (LPCOMPOSITIONFORM
)buffer
);
1771 ok(ret
== 0, "Destroyed IME should return 0\n");
1772 ret
= GetLastError();
1773 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1775 /* Test ImmGetCompositionStringA */
1776 SetLastError(0xdeadbeef);
1777 ret
= ImmGetCompositionStringA(imc_bad
, GCS_COMPSTR
, NULL
, 0);
1778 ok(ret
== 0, "Bad IME should return 0\n");
1779 ret
= GetLastError();
1780 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1781 SetLastError(0xdeadbeef);
1782 ret
= ImmGetCompositionStringA(imc_null
, GCS_COMPSTR
, NULL
, 0);
1783 ok(ret
== 0, "NULL IME should return 0\n");
1784 ret
= GetLastError();
1785 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1786 SetLastError(0xdeadbeef);
1787 ret
= ImmGetCompositionStringA(imc_destroy
, GCS_COMPSTR
, NULL
, 0);
1788 ok(ret
== 0, "Destroyed IME should return 0\n");
1789 ret
= GetLastError();
1790 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1792 /* Test ImmSetOpenStatus */
1793 SetLastError(0xdeadbeef);
1794 ret
= ImmSetOpenStatus(imc_bad
, 1);
1795 ok(ret
== 0, "Bad IME should return 0\n");
1796 ret
= GetLastError();
1797 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1798 SetLastError(0xdeadbeef);
1799 ret
= ImmSetOpenStatus(imc_null
, 1);
1800 ok(ret
== 0, "NULL IME should return 0\n");
1801 ret
= GetLastError();
1802 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1803 SetLastError(0xdeadbeef);
1804 ret
= ImmSetOpenStatus(imc_destroy
, 1);
1805 ok(ret
== 0, "Destroyed IME should return 0\n");
1806 ret
= GetLastError();
1807 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1809 /* Test ImmGetOpenStatus */
1810 SetLastError(0xdeadbeef);
1811 ret
= ImmGetOpenStatus(imc_bad
);
1812 ok(ret
== 0, "Bad IME should return 0\n");
1813 ret
= GetLastError();
1814 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1815 SetLastError(0xdeadbeef);
1816 ret
= ImmGetOpenStatus(imc_null
);
1817 ok(ret
== 0, "NULL IME should return 0\n");
1818 ret
= GetLastError();
1819 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1820 SetLastError(0xdeadbeef);
1821 ret
= ImmGetOpenStatus(imc_destroy
);
1822 ok(ret
== 0, "Destroyed IME should return 0\n");
1823 ret
= GetLastError();
1824 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1826 /* Test ImmGetStatusWindowPos */
1827 SetLastError(0xdeadbeef);
1828 ret
= ImmGetStatusWindowPos(imc_bad
, NULL
);
1829 ok(ret
== 0, "Bad IME should return 0\n");
1830 ret
= GetLastError();
1831 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1832 SetLastError(0xdeadbeef);
1833 ret
= ImmGetStatusWindowPos(imc_null
, NULL
);
1834 ok(ret
== 0, "NULL IME should return 0\n");
1835 ret
= GetLastError();
1836 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1837 SetLastError(0xdeadbeef);
1838 ret
= ImmGetStatusWindowPos(imc_destroy
, NULL
);
1839 ok(ret
== 0, "Destroyed IME should return 0\n");
1840 ret
= GetLastError();
1841 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1843 /* Test ImmRequestMessageA */
1844 SetLastError(0xdeadbeef);
1845 ret
= ImmRequestMessageA(imc_bad
, WM_CHAR
, 0);
1846 ok(ret
== 0, "Bad IME should return 0\n");
1847 ret
= GetLastError();
1848 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1849 SetLastError(0xdeadbeef);
1850 ret
= ImmRequestMessageA(imc_null
, WM_CHAR
, 0);
1851 ok(ret
== 0, "NULL IME should return 0\n");
1852 ret
= GetLastError();
1853 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1854 SetLastError(0xdeadbeef);
1855 ret
= ImmRequestMessageA(imc_destroy
, WM_CHAR
, 0);
1856 ok(ret
== 0, "Destroyed IME should return 0\n");
1857 ret
= GetLastError();
1858 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1860 /* Test ImmSetCompositionFontA */
1861 SetLastError(0xdeadbeef);
1862 ret
= ImmSetCompositionFontA(imc_bad
, &lf
);
1863 ok(ret
== 0, "Bad IME should return 0\n");
1864 ret
= GetLastError();
1865 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1866 SetLastError(0xdeadbeef);
1867 ret
= ImmSetCompositionFontA(imc_null
, &lf
);
1868 ok(ret
== 0, "NULL IME should return 0\n");
1869 ret
= GetLastError();
1870 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1871 SetLastError(0xdeadbeef);
1872 ret
= ImmSetCompositionFontA(imc_destroy
, &lf
);
1873 ok(ret
== 0, "Destroyed IME should return 0\n");
1874 ret
= GetLastError();
1875 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1877 /* Test ImmSetCompositionWindow */
1878 SetLastError(0xdeadbeef);
1879 ret
= ImmSetCompositionWindow(imc_bad
, NULL
);
1880 ok(ret
== 0, "Bad IME should return 0\n");
1881 ret
= GetLastError();
1882 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1883 SetLastError(0xdeadbeef);
1884 ret
= ImmSetCompositionWindow(imc_null
, NULL
);
1885 ok(ret
== 0, "NULL IME should return 0\n");
1886 ret
= GetLastError();
1887 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1888 SetLastError(0xdeadbeef);
1889 ret
= ImmSetCompositionWindow(imc_destroy
, NULL
);
1890 ok(ret
== 0, "Destroyed IME should return 0\n");
1891 ret
= GetLastError();
1892 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1894 /* Test ImmSetConversionStatus */
1895 SetLastError(0xdeadbeef);
1896 ret
= ImmSetConversionStatus(imc_bad
, 0, 0);
1897 ok(ret
== 0, "Bad IME should return 0\n");
1898 ret
= GetLastError();
1899 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1900 SetLastError(0xdeadbeef);
1901 ret
= ImmSetConversionStatus(imc_null
, 0, 0);
1902 ok(ret
== 0, "NULL IME should return 0\n");
1903 ret
= GetLastError();
1904 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1905 SetLastError(0xdeadbeef);
1906 ret
= ImmSetConversionStatus(imc_destroy
, 0, 0);
1907 ok(ret
== 0, "Destroyed IME should return 0\n");
1908 ret
= GetLastError();
1909 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1911 /* Test ImmSetStatusWindowPos */
1912 SetLastError(0xdeadbeef);
1913 ret
= ImmSetStatusWindowPos(imc_bad
, 0);
1914 ok(ret
== 0, "Bad IME should return 0\n");
1915 ret
= GetLastError();
1916 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1917 SetLastError(0xdeadbeef);
1918 ret
= ImmSetStatusWindowPos(imc_null
, 0);
1919 ok(ret
== 0, "NULL IME should return 0\n");
1920 ret
= GetLastError();
1921 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1922 SetLastError(0xdeadbeef);
1923 ret
= ImmSetStatusWindowPos(imc_destroy
, 0);
1924 ok(ret
== 0, "Destroyed IME should return 0\n");
1925 ret
= GetLastError();
1926 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1928 /* Test ImmGetImeMenuItemsA */
1929 SetLastError(0xdeadbeef);
1930 ret
= ImmGetImeMenuItemsA(imc_bad
, 0, 0, NULL
, NULL
, 0);
1931 ok(ret
== 0, "Bad IME should return 0\n");
1932 ret
= GetLastError();
1933 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1934 SetLastError(0xdeadbeef);
1935 ret
= ImmGetImeMenuItemsA(imc_null
, 0, 0, NULL
, NULL
, 0);
1936 ok(ret
== 0, "NULL IME should return 0\n");
1937 ret
= GetLastError();
1938 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1939 SetLastError(0xdeadbeef);
1940 ret
= ImmGetImeMenuItemsA(imc_destroy
, 0, 0, NULL
, NULL
, 0);
1941 ok(ret
== 0, "Destroyed IME should return 0\n");
1942 ret
= GetLastError();
1943 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1945 /* Test ImmLockIMC */
1946 SetLastError(0xdeadbeef);
1947 ic
= ImmLockIMC(imc_bad
);
1948 ok(ic
== 0, "Bad IME should return 0\n");
1949 ret
= GetLastError();
1950 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1951 SetLastError(0xdeadbeef);
1952 ic
= ImmLockIMC(imc_null
);
1953 ok(ic
== 0, "NULL IME should return 0\n");
1954 ret
= GetLastError();
1955 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1956 SetLastError(0xdeadbeef);
1957 ic
= ImmLockIMC(imc_destroy
);
1958 ok(ic
== 0, "Destroyed IME should return 0\n");
1959 ret
= GetLastError();
1960 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1962 /* Test ImmUnlockIMC */
1963 SetLastError(0xdeadbeef);
1964 ret
= ImmUnlockIMC(imc_bad
);
1965 ok(ret
== 0, "Bad IME should return 0\n");
1966 ret
= GetLastError();
1967 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1968 SetLastError(0xdeadbeef);
1969 ret
= ImmUnlockIMC(imc_null
);
1970 ok(ret
== 0, "NULL IME should return 0\n");
1971 ret
= GetLastError();
1972 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1973 SetLastError(0xdeadbeef);
1974 ret
= ImmUnlockIMC(imc_destroy
);
1975 ok(ret
== 0, "Destroyed IME should return 0\n");
1976 ret
= GetLastError();
1977 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1979 /* Test ImmGenerateMessage */
1980 SetLastError(0xdeadbeef);
1981 ret
= ImmGenerateMessage(imc_bad
);
1982 ok(ret
== 0, "Bad IME should return 0\n");
1983 ret
= GetLastError();
1984 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1985 SetLastError(0xdeadbeef);
1986 ret
= ImmGenerateMessage(imc_null
);
1987 ok(ret
== 0, "NULL IME should return 0\n");
1988 ret
= GetLastError();
1989 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1990 SetLastError(0xdeadbeef);
1991 ret
= ImmGenerateMessage(imc_destroy
);
1992 ok(ret
== 0, "Destroyed IME should return 0\n");
1993 ret
= GetLastError();
1994 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2000 test_ImmNotifyIME();
2001 test_ImmGetCompositionString();
2002 test_ImmSetCompositionString();
2004 test_ImmAssociateContextEx();
2006 test_ImmIsUIMessage();
2007 test_ImmGetContext();
2008 test_ImmGetDescription();
2009 test_ImmDefaultHwnd();
2010 test_default_ime_window_creation();
2011 test_ImmGetIMCLockCount();
2012 test_ImmGetIMCCLockCount();
2013 test_ImmDestroyContext();
2014 test_ImmDestroyIMCC();
2017 /* Reinitialize the hooks to capture all windows */
2022 test_ime_processkey();
2023 else win_skip("SendInput is not available\n");