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
25 #define WIN32_NO_STATUS
29 #include "wine/test.h"
38 static const char *debugstr_ok( const char *cond
)
41 /* skip possible casts */
48 if (!strchr( cond
- 1, '(' )) return wine_dbg_sprintf( "got %s", cond
- 1 );
49 return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond
- 1, "( " ), cond
- 1 );
52 #define ok_eq( e, r, t, f, ... ) \
56 ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
58 #define ok_ne( e, r, t, f, ... ) \
62 ok( v != (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
64 #define ok_wcs( e, r ) \
67 const WCHAR *v = (r); \
68 ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \
70 #define ok_str( e, r ) \
73 const char *v = (r); \
74 ok( !strcmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_a(v) ); \
76 #define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() )
78 BOOL WINAPI
ImmSetActiveContext(HWND
, HIMC
, BOOL
);
80 static BOOL (WINAPI
*pImmAssociateContextEx
)(HWND
,HIMC
,DWORD
);
81 static UINT (WINAPI
*pNtUserAssociateInputContext
)(HWND
,HIMC
,ULONG
);
82 static BOOL (WINAPI
*pImmIsUIMessageA
)(HWND
,UINT
,WPARAM
,LPARAM
);
83 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
85 extern BOOL WINAPI
ImmFreeLayout(HKL
);
86 extern BOOL WINAPI
ImmLoadIME(HKL
);
87 extern BOOL WINAPI
ImmActivateLayout(HKL
);
89 #define DEFINE_EXPECT(func) \
90 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE
92 #define SET_EXPECT(func) \
93 expect_ ## func = TRUE
95 #define CHECK_EXPECT2(func) \
97 if (enabled_ ## func) {\
98 ok(expect_ ##func, "unexpected call " #func "\n"); \
99 called_ ## func = TRUE; \
103 #define CHECK_EXPECT(func) \
105 CHECK_EXPECT2(func); \
106 expect_ ## func = FALSE; \
109 #define CHECK_CALLED(func) \
111 ok(called_ ## func, "expected " #func "\n"); \
112 expect_ ## func = called_ ## func = FALSE; \
115 #define SET_ENABLE(func, val) \
116 enabled_ ## func = (val)
118 DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
119 DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
121 static void process_messages(void)
125 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
))
127 TranslateMessage( &msg
);
128 DispatchMessageA( &msg
);
133 * msgspy - record and analyse message traces sent to a certain window
135 typedef struct _msgs
{
140 static struct _msg_spy
{
143 HHOOK call_wnd_proc_hook
;
159 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
161 static LRESULT CALLBACK
get_msg_filter(int nCode
, WPARAM wParam
, LPARAM lParam
)
163 if (HC_ACTION
== nCode
) {
164 MSG
*msg
= (MSG
*)lParam
;
166 if ((msg
->hwnd
== msg_spy
.hwnd
|| msg_spy
.hwnd
== NULL
) &&
167 (msg_spy
.i_msg
< ARRAY_SIZE(msg_spy
.msgs
)))
169 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.hwnd
= msg
->hwnd
;
170 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.message
= msg
->message
;
171 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.wParam
= msg
->wParam
;
172 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.lParam
= msg
->lParam
;
173 msg_spy
.msgs
[msg_spy
.i_msg
].post
= TRUE
;
178 return CallNextHookEx(msg_spy
.get_msg_hook
, nCode
, wParam
, lParam
);
181 static LRESULT CALLBACK
call_wnd_proc_filter(int nCode
, WPARAM wParam
,
184 if (HC_ACTION
== nCode
) {
185 CWPSTRUCT
*cwp
= (CWPSTRUCT
*)lParam
;
187 if (((cwp
->hwnd
== msg_spy
.hwnd
|| msg_spy
.hwnd
== NULL
)) &&
188 (msg_spy
.i_msg
< ARRAY_SIZE(msg_spy
.msgs
)))
190 memcpy(&msg_spy
.msgs
[msg_spy
.i_msg
].msg
, cwp
, sizeof(msg_spy
.msgs
[0].msg
));
191 msg_spy
.msgs
[msg_spy
.i_msg
].post
= FALSE
;
196 return CallNextHookEx(msg_spy
.call_wnd_proc_hook
, nCode
, wParam
, lParam
);
199 static void msg_spy_pump_msg_queue(void) {
202 while(PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
203 TranslateMessage(&msg
);
204 DispatchMessageW(&msg
);
210 static void msg_spy_flush_msgs(void) {
211 msg_spy_pump_msg_queue();
215 static imm_msgs
* msg_spy_find_next_msg(UINT message
, UINT
*start
) {
218 msg_spy_pump_msg_queue();
220 if (msg_spy
.i_msg
>= ARRAY_SIZE(msg_spy
.msgs
))
221 fprintf(stdout
, "%s:%d: msg_spy: message buffer overflow!\n",
224 for (i
= *start
; i
< msg_spy
.i_msg
; i
++)
225 if (msg_spy
.msgs
[i
].msg
.message
== message
)
228 return &msg_spy
.msgs
[i
];
234 static imm_msgs
* msg_spy_find_msg(UINT message
) {
237 return msg_spy_find_next_msg(message
, &i
);
240 static void msg_spy_init(HWND hwnd
) {
242 msg_spy
.get_msg_hook
=
243 SetWindowsHookExW(WH_GETMESSAGE
, get_msg_filter
, GetModuleHandleW(NULL
),
244 GetCurrentThreadId());
245 msg_spy
.call_wnd_proc_hook
=
246 SetWindowsHookExW(WH_CALLWNDPROC
, call_wnd_proc_filter
,
247 GetModuleHandleW(NULL
), GetCurrentThreadId());
250 msg_spy_flush_msgs();
253 static void msg_spy_cleanup(void) {
254 if (msg_spy
.get_msg_hook
)
255 UnhookWindowsHookEx(msg_spy
.get_msg_hook
);
256 if (msg_spy
.call_wnd_proc_hook
)
257 UnhookWindowsHookEx(msg_spy
.call_wnd_proc_hook
);
258 memset(&msg_spy
, 0, sizeof(msg_spy
));
262 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the
263 * messages being sent to this window in response.
265 static const char wndcls
[] = "winetest_imm32_wndcls";
266 static enum { PHASE_UNKNOWN
, FIRST_WINDOW
, SECOND_WINDOW
,
267 CREATE_CANCEL
, NCCREATE_CANCEL
, IME_DISABLED
} test_phase
;
268 static HWND hwnd
, child
;
270 static HWND
get_ime_window(void);
272 static void load_resource( const WCHAR
*name
, WCHAR
*filename
)
274 static WCHAR path
[MAX_PATH
];
280 GetTempPathW( ARRAY_SIZE(path
), path
);
281 GetTempFileNameW( path
, name
, 0, filename
);
283 file
= CreateFileW( filename
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0 );
284 ok( file
!= INVALID_HANDLE_VALUE
, "failed to create %s, error %lu\n", debugstr_w(filename
), GetLastError() );
286 res
= FindResourceW( NULL
, name
, L
"TESTDLL" );
287 ok( res
!= 0, "couldn't find resource\n" );
288 ptr
= LockResource( LoadResource( GetModuleHandleW( NULL
), res
) );
289 WriteFile( file
, ptr
, SizeofResource( GetModuleHandleW( NULL
), res
), &written
, NULL
);
290 ok( written
== SizeofResource( GetModuleHandleW( NULL
), res
), "couldn't write resource\n" );
294 static LRESULT WINAPI
wndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
296 HWND default_ime_wnd
;
299 case WM_IME_SETCONTEXT
:
300 if (wParam
) CHECK_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
301 else CHECK_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
302 ok(lParam
== ISC_SHOWUIALL
|| !lParam
, "lParam = %Ix\n", lParam
);
305 default_ime_wnd
= get_ime_window();
309 ok(!default_ime_wnd
, "expected no IME windows\n");
312 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
315 break; /* do nothing */
317 if (test_phase
== NCCREATE_CANCEL
)
321 default_ime_wnd
= get_ime_window();
326 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
329 ok(!default_ime_wnd
, "expected no IME windows\n");
332 break; /* do nothing */
336 default_ime_wnd
= get_ime_window();
341 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
344 ok(!default_ime_wnd
, "expected no IME windows\n");
347 break; /* do nothing */
349 if (test_phase
== CREATE_CANCEL
)
354 return DefWindowProcA(hWnd
,msg
,wParam
,lParam
);
357 static BOOL
is_ime_enabled(void)
362 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
363 ok(wnd
!= NULL
, "CreateWindow failed\n");
365 himc
= ImmGetContext(wnd
);
372 ImmReleaseContext(wnd
, himc
);
377 static BOOL
init(void) {
381 hmod
= GetModuleHandleA("imm32.dll");
382 huser
= GetModuleHandleA("user32");
383 pImmAssociateContextEx
= (void*)GetProcAddress(hmod
, "ImmAssociateContextEx");
384 pImmIsUIMessageA
= (void*)GetProcAddress(hmod
, "ImmIsUIMessageA");
385 pSendInput
= (void*)GetProcAddress(huser
, "SendInput");
386 pNtUserAssociateInputContext
= (void*)GetProcAddress(GetModuleHandleW(L
"win32u.dll"),
387 "NtUserAssociateInputContext");
389 wc
.cbSize
= sizeof(WNDCLASSEXA
);
391 wc
.lpfnWndProc
= wndProc
;
394 wc
.hInstance
= GetModuleHandleA(NULL
);
395 wc
.hIcon
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
396 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
397 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
398 wc
.lpszMenuName
= NULL
;
399 wc
.lpszClassName
= wndcls
;
400 wc
.hIconSm
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
402 if (!RegisterClassExA(&wc
))
405 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
406 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
407 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
411 child
= CreateWindowA("edit", "edit", WS_CHILD
| WS_VISIBLE
, 0, 0, 50, 50, hwnd
, 0, 0, 0);
415 ShowWindow(hwnd
, SW_SHOWNORMAL
);
423 static void cleanup(void) {
427 UnregisterClassA(wndcls
, GetModuleHandleW(NULL
));
430 static void test_ImmNotifyIME(void) {
431 static const char string
[] = "wine";
432 char resstr
[16] = "";
436 imc
= ImmGetContext(hwnd
);
437 msg_spy_flush_msgs();
439 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
442 "Canceling an empty composition string should succeed.\n");
443 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
444 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
445 "the composition string being canceled is empty.\n");
447 ImmSetCompositionStringA(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
, 0);
448 msg_spy_flush_msgs();
450 ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
451 msg_spy_flush_msgs();
453 /* behavior differs between win9x and NT */
454 ret
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, resstr
, sizeof(resstr
));
455 ok(!ret
, "After being cancelled the composition string is empty.\n");
457 msg_spy_flush_msgs();
459 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
462 "Canceling an empty composition string should succeed.\n");
463 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
464 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
465 "the composition string being canceled is empty.\n");
467 msg_spy_flush_msgs();
468 ImmReleaseContext(hwnd
, imc
);
470 imc
= ImmCreateContext();
471 ImmDestroyContext(imc
);
473 SetLastError(0xdeadbeef);
474 ret
= ImmNotifyIME((HIMC
)0xdeadcafe, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
475 ok (ret
== 0, "Bad IME should return 0\n");
476 ret
= GetLastError();
477 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
478 SetLastError(0xdeadbeef);
479 ret
= ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
480 ok (ret
== 0, "NULL IME should return 0\n");
481 ret
= GetLastError();
482 ok(ret
== ERROR_SUCCESS
, "wrong last error %08x!\n", ret
);
483 SetLastError(0xdeadbeef);
484 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
485 ok (ret
== 0, "Destroyed IME should return 0\n");
486 ret
= GetLastError();
487 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
492 WNDPROC old_wnd_proc
;
493 BOOL catch_result_str
;
497 } ime_composition_test
;
499 static LRESULT WINAPI
test_ime_wnd_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
503 case WM_IME_COMPOSITION
:
504 if ((lParam
& GCS_RESULTSTR
) && !ime_composition_test
.catch_result_str
) {
511 hwndIme
= ImmGetDefaultIMEWnd(hWnd
);
512 ok(hwndIme
!= NULL
, "expected IME window existence\n");
514 ok(!ime_composition_test
.catch_ime_char
, "WM_IME_CHAR is sent\n");
515 ret
= CallWindowProcA(ime_composition_test
.old_wnd_proc
,
516 hWnd
, msg
, wParam
, lParam
);
517 ok(ime_composition_test
.catch_ime_char
, "WM_IME_CHAR isn't sent\n");
519 ime_composition_test
.catch_ime_char
= FALSE
;
520 SendMessageA(hwndIme
, msg
, wParam
, lParam
);
521 ok(!ime_composition_test
.catch_ime_char
, "WM_IME_CHAR is sent\n");
523 imc
= ImmGetContext(hWnd
);
524 size
= ImmGetCompositionStringW(imc
, GCS_RESULTSTR
,
525 wstring
, sizeof(wstring
));
526 ok(size
> 0, "ImmGetCompositionString(GCS_RESULTSTR) is %ld\n", size
);
527 ImmReleaseContext(hwnd
, imc
);
529 ime_composition_test
.catch_result_str
= TRUE
;
534 if (!ime_composition_test
.catch_result_str
)
535 ime_composition_test
.catch_ime_char
= TRUE
;
538 if (wParam
== ime_composition_test
.timer_id
) {
539 HWND parent
= GetParent(hWnd
);
541 int left
= 20 - (GetTickCount() - ime_composition_test
.start
) / 1000;
542 wsprintfA(title
, "%sLeft %d sec. - IME composition test",
543 ime_composition_test
.catch_result_str
? "[*] " : "", left
);
544 SetWindowTextA(parent
, title
);
546 DestroyWindow(parent
);
548 SetTimer(hWnd
, wParam
, 100, NULL
);
553 return CallWindowProcA(ime_composition_test
.old_wnd_proc
,
554 hWnd
, msg
, wParam
, lParam
);
557 static void test_ImmGetCompositionString(void)
560 static const WCHAR string
[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
568 imc
= ImmGetContext(hwnd
);
569 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
,0);
571 win_skip("Composition isn't supported\n");
572 ImmReleaseContext(hwnd
, imc
);
575 msg_spy_flush_msgs();
577 alen
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 20);
578 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 20);
579 /* windows machines without any IME installed just return 0 above */
582 len
= ImmGetCompositionStringW(imc
, GCS_COMPATTR
, NULL
, 0);
583 ok(len
*sizeof(WCHAR
)==wlen
,"GCS_COMPATTR(W) not returning correct count\n");
584 len
= ImmGetCompositionStringA(imc
, GCS_COMPATTR
, NULL
, 0);
585 ok(len
==alen
,"GCS_COMPATTR(A) not returning correct count\n");
587 /* Get strings with exactly matching buffer sizes. */
588 memset(wstring
, 0x1a, sizeof(wstring
));
589 memset(cstring
, 0x1a, sizeof(cstring
));
591 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, alen
);
592 ok(len
== alen
, "Unexpected length %ld.\n", len
);
593 ok(cstring
[alen
] == 0x1a, "Unexpected buffer contents.\n");
595 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, wlen
);
596 ok(len
== wlen
, "Unexpected length %ld.\n", len
);
597 ok(wstring
[wlen
/sizeof(WCHAR
)] == 0x1a1a, "Unexpected buffer contents.\n");
599 /* Get strings with exactly smaller buffer sizes. */
600 memset(wstring
, 0x1a, sizeof(wstring
));
601 memset(cstring
, 0x1a, sizeof(cstring
));
603 /* Returns 0 but still fills buffer. */
604 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, alen
- 1);
605 ok(!len
, "Unexpected length %ld.\n", len
);
606 ok(cstring
[0] == 'w', "Unexpected buffer contents %s.\n", cstring
);
608 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, wlen
- 1);
609 ok(len
== wlen
- 1, "Unexpected length %ld.\n", len
);
610 ok(!memcmp(wstring
, string
, wlen
- 1), "Unexpected buffer contents.\n");
612 /* Get the size of the required output buffer. */
613 memset(wstring
, 0x1a, sizeof(wstring
));
614 memset(cstring
, 0x1a, sizeof(cstring
));
616 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 0);
617 ok(len
== alen
, "Unexpected length %ld.\n", len
);
618 ok(cstring
[0] == 0x1a, "Unexpected buffer contents %s.\n", cstring
);
620 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 0);
621 ok(len
== wlen
, "Unexpected length %ld.\n", len
);
622 ok(wstring
[0] == 0x1a1a, "Unexpected buffer contents.\n");
625 win_skip("Composition string isn't available\n");
627 ImmReleaseContext(hwnd
, imc
);
629 /* Test composition results input by IMM API */
630 prop
= ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR
);
631 if (!(prop
& SCS_CAP_COMPSTR
)) {
632 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */
633 skip("This IME doesn't support SCS_SETSTR\n");
636 ime_composition_test
.old_wnd_proc
=
637 (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
638 (LONG_PTR
)test_ime_wnd_proc
);
639 imc
= ImmGetContext(hwnd
);
640 msg_spy_flush_msgs();
642 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
,
643 string
, sizeof(string
), NULL
,0);
644 ok(ret
, "ImmSetCompositionStringW failed\n");
645 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
,
646 wstring
, sizeof(wstring
));
648 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
649 ok(ret
, "ImmNotifyIME(CPS_COMPLETE) failed\n");
650 msg_spy_flush_msgs();
651 ok(ime_composition_test
.catch_result_str
,
652 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n");
655 win_skip("Composition string isn't available\n");
656 ImmReleaseContext(hwnd
, imc
);
657 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
658 (LONG_PTR
)ime_composition_test
.old_wnd_proc
);
659 msg_spy_flush_msgs();
662 /* Test composition results input by hand */
663 memset(&ime_composition_test
, 0, sizeof(ime_composition_test
));
664 if (winetest_interactive
) {
665 HWND hwndMain
, hwndChild
;
667 const DWORD MY_TIMER
= 0xcaffe;
669 hwndMain
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
,
670 "IME composition test",
671 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
672 CW_USEDEFAULT
, CW_USEDEFAULT
, 320, 160,
673 NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
674 hwndChild
= CreateWindowExA(0, "static",
675 "Input a DBCS character here using IME.",
676 WS_CHILD
| WS_VISIBLE
,
677 0, 0, 320, 100, hwndMain
, NULL
,
678 GetModuleHandleA(NULL
), NULL
);
680 ime_composition_test
.old_wnd_proc
=
681 (WNDPROC
)SetWindowLongPtrA(hwndChild
, GWLP_WNDPROC
,
682 (LONG_PTR
)test_ime_wnd_proc
);
686 ime_composition_test
.timer_id
= MY_TIMER
;
687 ime_composition_test
.start
= GetTickCount();
688 SetTimer(hwndChild
, ime_composition_test
.timer_id
, 100, NULL
);
689 while (GetMessageA(&msg
, NULL
, 0, 0)) {
690 TranslateMessage(&msg
);
691 DispatchMessageA(&msg
);
692 if (!IsWindow(hwndMain
))
695 if (!ime_composition_test
.catch_result_str
)
696 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n");
697 msg_spy_flush_msgs();
701 static void test_ImmSetCompositionString(void)
706 SetLastError(0xdeadbeef);
707 imc
= ImmGetContext(hwnd
);
708 ok(imc
!= 0, "ImmGetContext() failed. Last error: %lu\n", GetLastError());
712 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, NULL
, 0, NULL
, 0);
715 "ImmSetCompositionStringW() failed.\n");
717 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
,
719 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
721 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGECLAUSE
,
723 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
725 ret
= ImmSetCompositionStringW(imc
, SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
727 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
729 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
731 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
733 ImmReleaseContext(hwnd
, imc
);
736 static void test_ImmIME(void)
740 imc
= ImmGetContext(hwnd
);
744 rc
= ImmConfigureIMEA(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
745 ok (rc
== 0, "ImmConfigureIMEA did not fail\n");
746 rc
= ImmConfigureIMEW(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
747 ok (rc
== 0, "ImmConfigureIMEW did not fail\n");
749 ImmReleaseContext(hwnd
,imc
);
752 static void test_ImmAssociateContextEx(void)
757 if (!pImmAssociateContextEx
) return;
759 imc
= ImmGetContext(hwnd
);
765 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
766 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
768 ok(GetActiveWindow() == hwnd
, "hwnd is not active\n");
769 newimc
= ImmCreateContext();
770 ok(newimc
!= imc
, "handles should not be the same\n");
771 rc
= pImmAssociateContextEx(NULL
, NULL
, 0);
772 ok(!rc
, "ImmAssociateContextEx succeeded\n");
773 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
774 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
775 rc
= pImmAssociateContextEx(hwnd
, NULL
, 0);
776 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
777 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
778 ok(rc
, "ImmAssociateContextEx failed\n");
779 rc
= pImmAssociateContextEx(NULL
, imc
, 0);
780 ok(!rc
, "ImmAssociateContextEx succeeded\n");
782 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
783 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
784 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
785 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
786 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
787 ok(rc
, "ImmAssociateContextEx failed\n");
788 retimc
= ImmGetContext(hwnd
);
789 ok(retimc
== imc
, "handles should be the same\n");
790 ImmReleaseContext(hwnd
,retimc
);
792 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
793 ok(rc
, "ImmAssociateContextEx failed\n");
795 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
796 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
797 rc
= pImmAssociateContextEx(hwnd
, newimc
, 0);
798 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
799 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
800 ok(rc
, "ImmAssociateContextEx failed\n");
801 retimc
= ImmGetContext(hwnd
);
802 ok(retimc
== newimc
, "handles should be the same\n");
803 ImmReleaseContext(hwnd
,retimc
);
805 focus
= CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0);
806 ok(focus
!= NULL
, "CreateWindow failed\n");
807 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
809 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
810 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
811 ok(rc
, "ImmAssociateContextEx failed\n");
812 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
813 DestroyWindow(focus
);
814 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
816 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
818 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
819 rc
= pImmAssociateContextEx(hwnd
, newimc
, 0);
820 ok(rc
, "ImmAssociateContextEx failed\n");
821 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
823 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
825 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
826 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
827 rc
= pImmAssociateContextEx(hwnd
, NULL
, IACE_DEFAULT
);
828 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
829 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
830 ok(rc
, "ImmAssociateContextEx failed\n");
832 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
833 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
835 ImmReleaseContext(hwnd
,imc
);
838 /* similar to above, but using NtUserAssociateInputContext */
839 static void test_NtUserAssociateInputContext(void)
844 if (!pNtUserAssociateInputContext
)
846 win_skip("NtUserAssociateInputContext not available\n");
850 imc
= ImmGetContext(hwnd
);
856 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
857 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
859 ok(GetActiveWindow() == hwnd
, "hwnd is not active\n");
860 newimc
= ImmCreateContext();
861 ok(newimc
!= imc
, "handles should not be the same\n");
862 rc
= pNtUserAssociateInputContext(NULL
, NULL
, 0);
863 ok(rc
== 2, "NtUserAssociateInputContext returned %x\n", rc
);
864 rc
= pNtUserAssociateInputContext(hwnd
, NULL
, 0);
865 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
866 rc
= pNtUserAssociateInputContext(NULL
, imc
, 0);
867 ok(rc
== 2, "NtUserAssociateInputContext returned %x\n", rc
);
869 rc
= pNtUserAssociateInputContext(hwnd
, imc
, 0);
870 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
871 retimc
= ImmGetContext(hwnd
);
872 ok(retimc
== imc
, "handles should be the same\n");
873 ImmReleaseContext(hwnd
,retimc
);
875 rc
= pNtUserAssociateInputContext(hwnd
, imc
, 0);
876 ok(rc
== 0, "NtUserAssociateInputContext returned %x\n", rc
);
878 rc
= pNtUserAssociateInputContext(hwnd
, newimc
, 0);
879 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
880 retimc
= ImmGetContext(hwnd
);
881 ok(retimc
== newimc
, "handles should be the same\n");
882 ImmReleaseContext(hwnd
,retimc
);
884 focus
= CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0);
885 ok(focus
!= NULL
, "CreateWindow failed\n");
886 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
888 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
889 rc
= pNtUserAssociateInputContext(hwnd
, imc
, 0);
890 ok(rc
== 0, "NtUserAssociateInputContext returned %x\n", rc
);
891 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
892 DestroyWindow(focus
);
893 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
895 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
897 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
898 rc
= pNtUserAssociateInputContext(hwnd
, newimc
, 0);
899 ok(rc
== 0, "NtUserAssociateInputContext returned %x\n", rc
);
900 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
902 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
904 rc
= pNtUserAssociateInputContext(hwnd
, NULL
, IACE_DEFAULT
);
905 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
907 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
908 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
910 ImmReleaseContext(hwnd
,imc
);
913 typedef struct _igc_threadinfo
{
921 static DWORD WINAPI
ImmGetContextThreadFunc( LPVOID lpParam
)
930 igc_threadinfo
*info
= (igc_threadinfo
*)lpParam
;
931 info
->hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
932 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
933 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
935 h1
= ImmGetContext(hwnd
);
936 ok(info
->himc
== h1
, "hwnd context changed in new thread\n");
937 h2
= ImmGetContext(info
->hwnd
);
938 ok(h2
!= h1
, "new hwnd in new thread should have different context\n");
940 ImmReleaseContext(hwnd
,h1
);
942 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
943 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
944 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
945 h1
= ImmGetContext(hwnd2
);
947 ok(h1
== h2
, "Windows in same thread should have same default context\n");
948 ImmReleaseContext(hwnd2
,h1
);
949 ImmReleaseContext(info
->hwnd
,h2
);
950 DestroyWindow(hwnd2
);
952 /* priming for later tests */
953 ImmSetCompositionWindow(h1
, &cf
);
954 ImmSetStatusWindowPos(h1
, &pt
);
955 info
->u_himc
= ImmCreateContext();
956 ImmSetOpenStatus(info
->u_himc
, TRUE
);
958 cdf
.dwStyle
= CFS_CANDIDATEPOS
;
959 cdf
.ptCurrentPos
.x
= 0;
960 cdf
.ptCurrentPos
.y
= 0;
961 ImmSetCandidateWindow(info
->u_himc
, &cdf
);
963 SetEvent(info
->event
);
965 while(GetMessageW(&msg
, 0, 0, 0))
967 TranslateMessage(&msg
);
968 DispatchMessageW(&msg
);
973 static void test_ImmThreads(void)
975 HIMC himc
, otherHimc
, h1
;
976 igc_threadinfo threadinfo
;
983 DWORD status
, sentence
;
986 himc
= ImmGetContext(hwnd
);
987 threadinfo
.event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
988 threadinfo
.himc
= himc
;
989 hThread
= CreateThread(NULL
, 0, ImmGetContextThreadFunc
, &threadinfo
, 0, &dwThreadId
);
990 WaitForSingleObject(threadinfo
.event
, INFINITE
);
992 otherHimc
= ImmGetContext(threadinfo
.hwnd
);
994 ok(himc
!= otherHimc
, "Windows from other threads should have different himc\n");
995 ok(otherHimc
== threadinfo
.himc
, "Context from other thread should not change in main thread\n");
997 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
998 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
999 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1000 rc
= ImmSetActiveContext(hwnd
, otherHimc
, TRUE
);
1001 ok(rc
, "ImmSetActiveContext failed\n");
1002 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1003 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1004 rc
= ImmSetActiveContext(hwnd
, otherHimc
, FALSE
);
1005 ok(rc
, "ImmSetActiveContext failed\n");
1006 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1007 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
1008 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
1010 h1
= ImmAssociateContext(hwnd
,otherHimc
);
1011 ok(h1
== NULL
, "Should fail to be able to Associate a default context from a different thread\n");
1012 h1
= ImmGetContext(hwnd
);
1013 ok(h1
== himc
, "Context for window should remain unchanged\n");
1014 ImmReleaseContext(hwnd
,h1
);
1016 h1
= ImmAssociateContext(hwnd
, threadinfo
.u_himc
);
1017 ok (h1
== NULL
, "Should fail to associate a context from a different thread\n");
1018 h1
= ImmGetContext(hwnd
);
1019 ok(h1
== himc
, "Context for window should remain unchanged\n");
1020 ImmReleaseContext(hwnd
,h1
);
1022 h1
= ImmAssociateContext(threadinfo
.hwnd
, threadinfo
.u_himc
);
1023 ok (h1
== NULL
, "Should fail to associate a context from a different thread into a window from that thread.\n");
1024 h1
= ImmGetContext(threadinfo
.hwnd
);
1025 ok(h1
== threadinfo
.himc
, "Context for window should remain unchanged\n");
1026 ImmReleaseContext(threadinfo
.hwnd
,h1
);
1029 rc
= ImmSetOpenStatus(himc
, TRUE
);
1030 ok(rc
!= 0, "ImmSetOpenStatus failed\n");
1031 rc
= ImmGetOpenStatus(himc
);
1032 ok(rc
!= 0, "ImmGetOpenStatus failed\n");
1033 rc
= ImmSetOpenStatus(himc
, FALSE
);
1034 ok(rc
!= 0, "ImmSetOpenStatus failed\n");
1035 rc
= ImmGetOpenStatus(himc
);
1036 ok(rc
== 0, "ImmGetOpenStatus failed\n");
1038 rc
= ImmSetOpenStatus(otherHimc
, TRUE
);
1039 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
1040 rc
= ImmSetOpenStatus(threadinfo
.u_himc
, TRUE
);
1041 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
1042 rc
= ImmGetOpenStatus(otherHimc
);
1043 ok(rc
== 0, "ImmGetOpenStatus failed\n");
1044 rc
= ImmGetOpenStatus(threadinfo
.u_himc
);
1045 ok (rc
== 1 || broken(rc
== 0), "ImmGetOpenStatus should return 1\n");
1046 rc
= ImmSetOpenStatus(otherHimc
, FALSE
);
1047 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
1048 rc
= ImmGetOpenStatus(otherHimc
);
1049 ok(rc
== 0, "ImmGetOpenStatus failed\n");
1051 /* CompositionFont */
1052 rc
= ImmGetCompositionFontA(himc
, &lf
);
1053 ok(rc
!= 0, "ImmGetCompositionFont failed\n");
1054 rc
= ImmSetCompositionFontA(himc
, &lf
);
1055 ok(rc
!= 0, "ImmSetCompositionFont failed\n");
1057 rc
= ImmGetCompositionFontA(otherHimc
, &lf
);
1058 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionFont failed\n");
1059 rc
= ImmGetCompositionFontA(threadinfo
.u_himc
, &lf
);
1060 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionFont user himc failed\n");
1061 rc
= ImmSetCompositionFontA(otherHimc
, &lf
);
1062 ok(rc
== 0, "ImmSetCompositionFont should fail\n");
1063 rc
= ImmSetCompositionFontA(threadinfo
.u_himc
, &lf
);
1064 ok(rc
== 0, "ImmSetCompositionFont should fail\n");
1066 /* CompositionString */
1067 rc
= ImmSetCompositionStringA(himc
, SCS_SETSTR
, "a", 2, NULL
, 0);
1068 ok(rc
, "failed.\n");
1069 rc
= ImmSetCompositionStringA(otherHimc
, SCS_SETSTR
, "a", 2, NULL
, 0);
1070 ok(!rc
, "should fail.\n");
1071 rc
= ImmSetCompositionStringA(threadinfo
.u_himc
, SCS_SETSTR
, "a", 2, NULL
, 0);
1072 ok(!rc
, "should fail.\n");
1074 /* CompositionWindow */
1075 rc
= ImmSetCompositionWindow(himc
, &cf
);
1076 ok(rc
!= 0, "ImmSetCompositionWindow failed\n");
1077 rc
= ImmGetCompositionWindow(himc
, &cf
);
1078 ok(rc
!= 0, "ImmGetCompositionWindow failed\n");
1080 rc
= ImmSetCompositionWindow(otherHimc
, &cf
);
1081 ok(rc
== 0, "ImmSetCompositionWindow should fail\n");
1082 rc
= ImmSetCompositionWindow(threadinfo
.u_himc
, &cf
);
1083 ok(rc
== 0, "ImmSetCompositionWindow should fail\n");
1084 rc
= ImmGetCompositionWindow(otherHimc
, &cf
);
1085 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionWindow failed\n");
1086 rc
= ImmGetCompositionWindow(threadinfo
.u_himc
, &cf
);
1087 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionWindow failed\n");
1089 /* ConversionStatus */
1090 rc
= ImmGetConversionStatus(himc
, &status
, &sentence
);
1091 ok(rc
!= 0, "ImmGetConversionStatus failed\n");
1092 rc
= ImmSetConversionStatus(himc
, status
, sentence
);
1093 ok(rc
!= 0, "ImmSetConversionStatus failed\n");
1095 rc
= ImmGetConversionStatus(otherHimc
, &status
, &sentence
);
1096 ok(rc
!= 0 || broken(rc
== 0), "ImmGetConversionStatus failed\n");
1097 rc
= ImmGetConversionStatus(threadinfo
.u_himc
, &status
, &sentence
);
1098 ok(rc
!= 0 || broken(rc
== 0), "ImmGetConversionStatus failed\n");
1099 rc
= ImmSetConversionStatus(otherHimc
, status
, sentence
);
1100 ok(rc
== 0, "ImmSetConversionStatus should fail\n");
1101 rc
= ImmSetConversionStatus(threadinfo
.u_himc
, status
, sentence
);
1102 ok(rc
== 0, "ImmSetConversionStatus should fail\n");
1104 /* StatusWindowPos */
1105 rc
= ImmSetStatusWindowPos(himc
, &pt
);
1106 ok(rc
!= 0, "ImmSetStatusWindowPos failed\n");
1107 rc
= ImmGetStatusWindowPos(himc
, &pt
);
1108 ok(rc
!= 0, "ImmGetStatusWindowPos failed\n");
1110 rc
= ImmSetStatusWindowPos(otherHimc
, &pt
);
1111 ok(rc
== 0, "ImmSetStatusWindowPos should fail\n");
1112 rc
= ImmSetStatusWindowPos(threadinfo
.u_himc
, &pt
);
1113 ok(rc
== 0, "ImmSetStatusWindowPos should fail\n");
1114 rc
= ImmGetStatusWindowPos(otherHimc
, &pt
);
1115 ok(rc
!= 0 || broken(rc
== 0), "ImmGetStatusWindowPos failed\n");
1116 rc
= ImmGetStatusWindowPos(threadinfo
.u_himc
, &pt
);
1117 ok(rc
!= 0 || broken(rc
== 0), "ImmGetStatusWindowPos failed\n");
1119 h1
= ImmAssociateContext(threadinfo
.hwnd
, NULL
);
1120 ok (h1
== otherHimc
, "ImmAssociateContext cross thread with NULL should work\n");
1121 h1
= ImmGetContext(threadinfo
.hwnd
);
1122 ok (h1
== NULL
, "CrossThread window context should be NULL\n");
1123 h1
= ImmAssociateContext(threadinfo
.hwnd
, h1
);
1124 ok (h1
== NULL
, "Resetting cross thread context should fail\n");
1125 h1
= ImmGetContext(threadinfo
.hwnd
);
1126 ok (h1
== NULL
, "CrossThread window context should still be NULL\n");
1128 rc
= ImmDestroyContext(threadinfo
.u_himc
);
1129 ok (rc
== 0, "ImmDestroyContext Cross Thread should fail\n");
1131 /* Candidate Window */
1132 rc
= ImmGetCandidateWindow(himc
, 0, &cdf
);
1133 ok (rc
== 0, "ImmGetCandidateWindow should fail\n");
1135 cdf
.dwStyle
= CFS_CANDIDATEPOS
;
1136 cdf
.ptCurrentPos
.x
= 0;
1137 cdf
.ptCurrentPos
.y
= 0;
1138 rc
= ImmSetCandidateWindow(himc
, &cdf
);
1139 ok (rc
== 1, "ImmSetCandidateWindow should succeed\n");
1140 rc
= ImmGetCandidateWindow(himc
, 0, &cdf
);
1141 ok (rc
== 1, "ImmGetCandidateWindow should succeed\n");
1143 rc
= ImmGetCandidateWindow(otherHimc
, 0, &cdf
);
1144 ok (rc
== 0, "ImmGetCandidateWindow should fail\n");
1145 rc
= ImmSetCandidateWindow(otherHimc
, &cdf
);
1146 ok (rc
== 0, "ImmSetCandidateWindow should fail\n");
1147 rc
= ImmGetCandidateWindow(threadinfo
.u_himc
, 0, &cdf
);
1148 ok (rc
== 1 || broken( rc
== 0), "ImmGetCandidateWindow should succeed\n");
1149 rc
= ImmSetCandidateWindow(threadinfo
.u_himc
, &cdf
);
1150 ok (rc
== 0, "ImmSetCandidateWindow should fail\n");
1152 ImmReleaseContext(threadinfo
.hwnd
,otherHimc
);
1153 ImmReleaseContext(hwnd
,himc
);
1155 SendMessageA(threadinfo
.hwnd
, WM_CLOSE
, 0, 0);
1156 rc
= PostThreadMessageA(dwThreadId
, WM_QUIT
, 1, 0);
1157 ok(rc
== 1, "PostThreadMessage should succeed\n");
1158 WaitForSingleObject(hThread
, INFINITE
);
1159 CloseHandle(hThread
);
1161 himc
= ImmGetContext(GetDesktopWindow());
1162 ok(himc
== NULL
, "Should not be able to get himc from other process window\n");
1165 static void test_ImmIsUIMessage(void)
1173 static const struct test tests
[] =
1175 { WM_MOUSEMOVE
, FALSE
},
1176 { WM_IME_STARTCOMPOSITION
, TRUE
},
1177 { WM_IME_ENDCOMPOSITION
, TRUE
},
1178 { WM_IME_COMPOSITION
, TRUE
},
1179 { WM_IME_SETCONTEXT
, TRUE
},
1180 { WM_IME_NOTIFY
, TRUE
},
1181 { WM_IME_CONTROL
, FALSE
},
1182 { WM_IME_COMPOSITIONFULL
, TRUE
},
1183 { WM_IME_SELECT
, TRUE
},
1184 { WM_IME_CHAR
, FALSE
},
1185 { 0x287 /* FIXME */, TRUE
},
1186 { WM_IME_REQUEST
, FALSE
},
1187 { WM_IME_KEYDOWN
, FALSE
},
1188 { WM_IME_KEYUP
, FALSE
},
1189 { 0, FALSE
} /* mark the end */
1192 UINT WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
1193 UINT WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
1194 UINT WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
1195 UINT WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
1196 UINT WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
1197 UINT WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
1198 UINT WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
1200 const struct test
*test
;
1203 if (!pImmIsUIMessageA
) return;
1205 for (test
= tests
; test
->msg
; test
++)
1207 msg_spy_flush_msgs();
1208 ret
= pImmIsUIMessageA(NULL
, test
->msg
, 0, 0);
1209 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
1210 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x for NULL hwnd\n", test
->msg
);
1212 ret
= pImmIsUIMessageA(hwnd
, test
->msg
, 0, 0);
1213 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
1215 ok(msg_spy_find_msg(test
->msg
) != NULL
, "Windows does send 0x%x\n", test
->msg
);
1217 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x\n", test
->msg
);
1220 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_SERVICE
, 0, 0);
1221 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n");
1222 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTOPTIONS
, 0, 0);
1223 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n");
1224 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_MOUSE
, 0, 0);
1225 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n");
1226 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTREQUEST
, 0, 0);
1227 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n");
1228 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERT
, 0, 0);
1229 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n");
1230 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_QUERYPOSITION
, 0, 0);
1231 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n");
1232 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_DOCUMENTFEED
, 0, 0);
1233 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n");
1236 static void test_ImmGetContext(void)
1241 SetLastError(0xdeadbeef);
1242 himc
= ImmGetContext((HWND
)0xffffffff);
1243 err
= GetLastError();
1244 ok(himc
== NULL
, "ImmGetContext succeeded\n");
1245 ok(err
== ERROR_INVALID_WINDOW_HANDLE
, "got %lu\n", err
);
1247 himc
= ImmGetContext(hwnd
);
1248 ok(himc
!= NULL
, "ImmGetContext failed\n");
1249 ok(ImmReleaseContext(hwnd
, himc
), "ImmReleaseContext failed\n");
1252 static LRESULT (WINAPI
*old_imm_wnd_proc
)(HWND
, UINT
, WPARAM
, LPARAM
);
1253 static LRESULT WINAPI
imm_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
1255 ok(msg
!= WM_DESTROY
, "got WM_DESTROY message\n");
1256 return old_imm_wnd_proc(hwnd
, msg
, wparam
, lparam
);
1259 static HWND thread_ime_wnd
;
1260 static DWORD WINAPI
test_ImmGetDefaultIMEWnd_thread(void *arg
)
1262 CreateWindowA("static", "static", WS_POPUP
, 0, 0, 1, 1, NULL
, NULL
, NULL
, NULL
);
1264 thread_ime_wnd
= ImmGetDefaultIMEWnd(0);
1265 ok(thread_ime_wnd
!= 0, "ImmGetDefaultIMEWnd returned NULL\n");
1266 old_imm_wnd_proc
= (void*)SetWindowLongPtrW(thread_ime_wnd
, GWLP_WNDPROC
, (LONG_PTR
)imm_wnd_proc
);
1270 static void test_ImmDefaultHwnd(void)
1272 HIMC imc1
, imc2
, imc3
;
1279 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1280 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1281 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1283 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1285 imc1
= ImmGetContext(hwnd
);
1288 win_skip("IME support not implemented\n");
1292 def1
= ImmGetDefaultIMEWnd(hwnd
);
1294 GetWindowTextA(def1
, title
, sizeof(title
));
1295 ok(!strcmp(title
, "Default IME"), "got %s\n", title
);
1296 style
= GetWindowLongA(def1
, GWL_STYLE
);
1297 ok(style
== (WS_DISABLED
| WS_POPUP
| WS_CLIPSIBLINGS
), "got %08lx\n", style
);
1298 style
= GetWindowLongA(def1
, GWL_EXSTYLE
);
1299 ok(style
== 0, "got %08lx\n", style
);
1301 imc2
= ImmCreateContext();
1302 ImmSetOpenStatus(imc2
, TRUE
);
1304 imc3
= ImmGetContext(hwnd
);
1305 def3
= ImmGetDefaultIMEWnd(hwnd
);
1307 ok(def3
== def1
, "Default IME window should not change\n");
1308 ok(imc1
== imc3
, "IME context should not change\n");
1309 ImmSetOpenStatus(imc2
, FALSE
);
1311 thread
= CreateThread(NULL
, 0, test_ImmGetDefaultIMEWnd_thread
, NULL
, 0, NULL
);
1312 WaitForSingleObject(thread
, INFINITE
);
1313 ok(thread_ime_wnd
!= def1
, "thread_ime_wnd == def1\n");
1314 ok(!IsWindow(thread_ime_wnd
), "thread_ime_wnd was not destroyed\n");
1315 CloseHandle(thread
);
1317 ImmReleaseContext(hwnd
, imc1
);
1318 ImmReleaseContext(hwnd
, imc3
);
1319 ImmDestroyContext(imc2
);
1320 DestroyWindow(hwnd
);
1323 static BOOL CALLBACK
is_ime_window_proc(HWND hWnd
, LPARAM param
)
1325 WCHAR class_nameW
[16];
1326 HWND
*ime_window
= (HWND
*)param
;
1327 if (GetClassNameW(hWnd
, class_nameW
, ARRAY_SIZE(class_nameW
)) && !lstrcmpW(class_nameW
, L
"IME"))
1335 static HWND
get_ime_window(void)
1337 HWND ime_window
= NULL
;
1338 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc
, (LPARAM
)&ime_window
);
1342 struct testcase_ime_window
{
1344 BOOL top_level_window
;
1347 static DWORD WINAPI
test_default_ime_window_cb(void *arg
)
1349 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1350 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1351 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
1353 ok(!get_ime_window(), "Expected no IME windows\n");
1354 if (testcase
->top_level_window
) {
1355 test_phase
= FIRST_WINDOW
;
1356 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1357 WS_OVERLAPPEDWINDOW
| visible
,
1358 CW_USEDEFAULT
, CW_USEDEFAULT
,
1359 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1362 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1364 CW_USEDEFAULT
, CW_USEDEFAULT
,
1365 240, 24, hwnd
, NULL
, GetModuleHandleW(NULL
), NULL
);
1367 ime_wnd
= get_ime_window();
1368 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
1369 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1370 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
1372 test_phase
= SECOND_WINDOW
;
1373 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1374 WS_OVERLAPPEDWINDOW
| visible
,
1375 CW_USEDEFAULT
, CW_USEDEFAULT
,
1376 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1377 DestroyWindow(hwnd2
);
1378 ok(IsWindow(ime_wnd
) ||
1379 broken(!testcase
->visible
/* Vista */) ||
1380 broken(!testcase
->top_level_window
/* Vista */) ,
1381 "Expected IME window existence\n");
1382 DestroyWindow(hwnd1
);
1384 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
1388 static DWORD WINAPI
test_default_ime_window_cancel_cb(void *arg
)
1390 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1391 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1392 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
1394 ok(!get_ime_window(), "Expected no IME windows\n");
1395 test_phase
= NCCREATE_CANCEL
;
1396 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1397 WS_OVERLAPPEDWINDOW
| visible
,
1398 CW_USEDEFAULT
, CW_USEDEFAULT
,
1399 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1400 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
1401 ok(!get_ime_window(), "Expected no IME windows\n");
1403 test_phase
= CREATE_CANCEL
;
1404 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1405 WS_OVERLAPPEDWINDOW
| visible
,
1406 CW_USEDEFAULT
, CW_USEDEFAULT
,
1407 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1408 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
1409 ok(!get_ime_window(), "Expected no IME windows\n");
1411 test_phase
= FIRST_WINDOW
;
1412 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1413 WS_OVERLAPPEDWINDOW
| visible
,
1414 CW_USEDEFAULT
, CW_USEDEFAULT
,
1415 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1416 ime_wnd
= get_ime_window();
1417 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
1418 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
1419 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
1421 DestroyWindow(hwnd2
);
1422 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
1426 static DWORD WINAPI
test_default_ime_disabled_cb(void *arg
)
1428 HWND hWnd
, default_ime_wnd
;
1430 ok(!get_ime_window(), "Expected no IME windows\n");
1431 ImmDisableIME(GetCurrentThreadId());
1432 test_phase
= IME_DISABLED
;
1433 hWnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1434 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1435 CW_USEDEFAULT
, CW_USEDEFAULT
,
1436 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1437 default_ime_wnd
= ImmGetDefaultIMEWnd(hWnd
);
1438 ok(!default_ime_wnd
, "Expected no IME windows\n");
1439 DestroyWindow(hWnd
);
1443 static DWORD WINAPI
test_default_ime_with_message_only_window_cb(void *arg
)
1445 HWND hwnd1
, hwnd2
, default_ime_wnd
;
1447 /* Message-only window doesn't create associated IME window. */
1448 test_phase
= PHASE_UNKNOWN
;
1449 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1450 WS_OVERLAPPEDWINDOW
,
1451 CW_USEDEFAULT
, CW_USEDEFAULT
,
1452 240, 120, HWND_MESSAGE
, NULL
, GetModuleHandleW(NULL
), NULL
);
1453 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1454 ok(!default_ime_wnd
, "Expected no IME windows, got %p\n", default_ime_wnd
);
1456 /* Setting message-only window as owner at creation,
1457 doesn't create associated IME window. */
1458 hwnd2
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1459 WS_OVERLAPPEDWINDOW
,
1460 CW_USEDEFAULT
, CW_USEDEFAULT
,
1461 240, 120, hwnd1
, NULL
, GetModuleHandleW(NULL
), NULL
);
1462 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
1463 todo_wine
ok(!default_ime_wnd
|| broken(IsWindow(default_ime_wnd
)), "Expected no IME windows, got %p\n", default_ime_wnd
);
1465 DestroyWindow(hwnd2
);
1466 DestroyWindow(hwnd1
);
1468 /* Making window message-only after creation,
1469 doesn't disassociate IME window. */
1470 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1471 WS_OVERLAPPEDWINDOW
,
1472 CW_USEDEFAULT
, CW_USEDEFAULT
,
1473 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1474 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1475 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1476 SetParent(hwnd1
, HWND_MESSAGE
);
1477 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1478 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1479 DestroyWindow(hwnd1
);
1483 static void test_default_ime_window_creation(void)
1487 struct testcase_ime_window testcases
[] = {
1488 /* visible, top-level window */
1495 for (i
= 0; i
< ARRAY_SIZE(testcases
); i
++)
1497 thread
= CreateThread(NULL
, 0, test_default_ime_window_cb
, &testcases
[i
], 0, NULL
);
1498 ok(thread
!= NULL
, "CreateThread failed with error %lu\n", GetLastError());
1499 while (MsgWaitForMultipleObjects(1, &thread
, FALSE
, INFINITE
, QS_ALLINPUT
) == WAIT_OBJECT_0
+ 1)
1502 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
1504 TranslateMessage(&msg
);
1505 DispatchMessageA(&msg
);
1508 CloseHandle(thread
);
1510 if (testcases
[i
].top_level_window
)
1512 thread
= CreateThread(NULL
, 0, test_default_ime_window_cancel_cb
, &testcases
[i
], 0, NULL
);
1513 ok(thread
!= NULL
, "CreateThread failed with error %lu\n", GetLastError());
1514 WaitForSingleObject(thread
, INFINITE
);
1515 CloseHandle(thread
);
1519 thread
= CreateThread(NULL
, 0, test_default_ime_disabled_cb
, NULL
, 0, NULL
);
1520 WaitForSingleObject(thread
, INFINITE
);
1521 CloseHandle(thread
);
1523 thread
= CreateThread(NULL
, 0, test_default_ime_with_message_only_window_cb
, NULL
, 0, NULL
);
1524 WaitForSingleObject(thread
, INFINITE
);
1525 CloseHandle(thread
);
1527 test_phase
= PHASE_UNKNOWN
;
1530 static void test_ImmGetIMCLockCount(void)
1533 DWORD count
, ret
, i
;
1536 imc
= ImmCreateContext();
1537 ImmDestroyContext(imc
);
1538 SetLastError(0xdeadbeef);
1539 count
= ImmGetIMCLockCount((HIMC
)0xdeadcafe);
1540 ok(count
== 0, "Invalid IMC should return 0\n");
1541 ret
= GetLastError();
1542 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1543 SetLastError(0xdeadbeef);
1544 count
= ImmGetIMCLockCount(0x00000000);
1545 ok(count
== 0, "NULL IMC should return 0\n");
1546 ret
= GetLastError();
1547 ok(ret
== 0xdeadbeef, "Last Error should remain unchanged: %08lx\n",ret
);
1548 count
= ImmGetIMCLockCount(imc
);
1549 ok(count
== 0, "Destroyed IMC should return 0\n");
1550 ret
= GetLastError();
1551 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1553 imc
= ImmCreateContext();
1554 count
= ImmGetIMCLockCount(imc
);
1555 ok(count
== 0, "expect 0, returned %ld\n", count
);
1556 ic
= ImmLockIMC(imc
);
1557 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1558 count
= ImmGetIMCLockCount(imc
);
1559 ok(count
== 1, "expect 1, returned %ld\n", count
);
1560 ret
= ImmUnlockIMC(imc
);
1561 ok(ret
== TRUE
, "expect TRUE, ret %ld\n", ret
);
1562 count
= ImmGetIMCLockCount(imc
);
1563 ok(count
== 0, "expect 0, returned %ld\n", count
);
1564 ret
= ImmUnlockIMC(imc
);
1565 ok(ret
== TRUE
, "expect TRUE, ret %ld\n", ret
);
1566 count
= ImmGetIMCLockCount(imc
);
1567 ok(count
== 0, "expect 0, returned %ld\n", count
);
1569 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
1571 ic
= ImmLockIMC(imc
);
1572 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1574 count
= ImmGetIMCLockCount(imc
);
1575 todo_wine
ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %ld\n", count
);
1577 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
1579 count
= ImmGetIMCLockCount(imc
);
1580 todo_wine
ok(count
== 1, "expect 1, returned %ld\n", count
);
1582 count
= ImmGetIMCLockCount(imc
);
1583 todo_wine
ok(count
== 0, "expect 0, returned %ld\n", count
);
1585 ImmDestroyContext(imc
);
1588 static void test_ImmGetIMCCLockCount(void)
1591 DWORD count
, g_count
, i
;
1595 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
1596 count
= ImmGetIMCCLockCount(imcc
);
1597 ok(count
== 0, "expect 0, returned %ld\n", count
);
1599 count
= ImmGetIMCCLockCount(imcc
);
1600 ok(count
== 1, "expect 1, returned %ld\n", count
);
1601 ret
= ImmUnlockIMCC(imcc
);
1602 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
1603 count
= ImmGetIMCCLockCount(imcc
);
1604 ok(count
== 0, "expect 0, returned %ld\n", count
);
1605 ret
= ImmUnlockIMCC(imcc
);
1606 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
1607 count
= ImmGetIMCCLockCount(imcc
);
1608 ok(count
== 0, "expect 0, returned %ld\n", count
);
1610 p
= ImmLockIMCC(imcc
);
1611 ok(GlobalHandle(p
) == imcc
, "expect %p, returned %p\n", imcc
, GlobalHandle(p
));
1613 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
1616 count
= ImmGetIMCCLockCount(imcc
);
1617 g_count
= GlobalFlags(imcc
) & GMEM_LOCKCOUNT
;
1618 ok(count
== g_count
, "count %ld, g_count %ld\n", count
, g_count
);
1620 count
= ImmGetIMCCLockCount(imcc
);
1621 ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %ld\n", count
);
1623 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
1625 count
= ImmGetIMCCLockCount(imcc
);
1626 ok(count
== 1, "expect 1, returned %ld\n", count
);
1628 count
= ImmGetIMCCLockCount(imcc
);
1629 ok(count
== 0, "expect 0, returned %ld\n", count
);
1631 ImmDestroyIMCC(imcc
);
1634 static void test_ImmDestroyContext(void)
1640 imc
= ImmCreateContext();
1641 count
= ImmGetIMCLockCount(imc
);
1642 ok(count
== 0, "expect 0, returned %ld\n", count
);
1643 ic
= ImmLockIMC(imc
);
1644 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1645 count
= ImmGetIMCLockCount(imc
);
1646 ok(count
== 1, "expect 1, returned %ld\n", count
);
1647 ret
= ImmDestroyContext(imc
);
1648 ok(ret
== TRUE
, "Destroy a locked IMC should success!\n");
1649 ic
= ImmLockIMC(imc
);
1650 ok(ic
== NULL
, "Lock a destroyed IMC should fail!\n");
1651 ret
= ImmUnlockIMC(imc
);
1652 ok(ret
== FALSE
, "Unlock a destroyed IMC should fail!\n");
1653 count
= ImmGetIMCLockCount(imc
);
1654 ok(count
== 0, "Get lock count of a destroyed IMC should return 0!\n");
1655 SetLastError(0xdeadbeef);
1656 ret
= ImmDestroyContext(imc
);
1657 ok(ret
== FALSE
, "Destroy a destroyed IMC should fail!\n");
1658 ret
= GetLastError();
1659 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1662 static void test_ImmDestroyIMCC(void)
1665 DWORD ret
, count
, size
;
1668 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
1669 count
= ImmGetIMCCLockCount(imcc
);
1670 ok(count
== 0, "expect 0, returned %ld\n", count
);
1671 p
= ImmLockIMCC(imcc
);
1672 ok(p
!= NULL
, "ImmLockIMCC failed!\n");
1673 count
= ImmGetIMCCLockCount(imcc
);
1674 ok(count
== 1, "expect 1, returned %ld\n", count
);
1675 size
= ImmGetIMCCSize(imcc
);
1676 ok(size
== sizeof(CANDIDATEINFO
), "returned %ld\n", size
);
1677 p
= ImmDestroyIMCC(imcc
);
1678 ok(p
== NULL
, "Destroy a locked IMCC should success!\n");
1679 p
= ImmLockIMCC(imcc
);
1680 ok(p
== NULL
, "Lock a destroyed IMCC should fail!\n");
1681 ret
= ImmUnlockIMCC(imcc
);
1682 ok(ret
== FALSE
, "Unlock a destroyed IMCC should return FALSE!\n");
1683 count
= ImmGetIMCCLockCount(imcc
);
1684 ok(count
== 0, "Get lock count of a destroyed IMCC should return 0!\n");
1685 size
= ImmGetIMCCSize(imcc
);
1686 ok(size
== 0, "Get size of a destroyed IMCC should return 0!\n");
1687 SetLastError(0xdeadbeef);
1688 p
= ImmDestroyIMCC(imcc
);
1689 ok(p
!= NULL
, "returned NULL\n");
1690 ret
= GetLastError();
1691 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1694 static void test_ImmMessages(void)
1702 LPINPUTCONTEXT lpIMC
;
1703 LPTRANSMSG lpTransMsg
;
1705 HWND hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1706 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1707 240, 120, NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
1709 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1710 defwnd
= ImmGetDefaultIMEWnd(hwnd
);
1711 imc
= ImmGetContext(hwnd
);
1713 ImmSetOpenStatus(imc
, TRUE
);
1714 msg_spy_flush_msgs();
1715 SendMessageA(defwnd
, WM_IME_CONTROL
, IMC_GETCANDIDATEPOS
, (LPARAM
)&cf
);
1718 msg
= msg_spy_find_next_msg(WM_IME_CONTROL
,&idx
);
1719 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1721 msg_spy_flush_msgs();
1723 lpIMC
= ImmLockIMC(imc
);
1724 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1725 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1726 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1727 lpTransMsg
->message
= WM_IME_STARTCOMPOSITION
;
1728 lpTransMsg
->wParam
= 0;
1729 lpTransMsg
->lParam
= 0;
1730 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1731 lpIMC
->dwNumMsgBuf
++;
1733 ImmGenerateMessage(imc
);
1737 msg
= msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION
, &idx
);
1738 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1740 msg_spy_flush_msgs();
1742 lpIMC
= ImmLockIMC(imc
);
1743 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1744 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1745 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1746 lpTransMsg
->message
= WM_IME_COMPOSITION
;
1747 lpTransMsg
->wParam
= 0;
1748 lpTransMsg
->lParam
= 0;
1749 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1750 lpIMC
->dwNumMsgBuf
++;
1752 ImmGenerateMessage(imc
);
1756 msg
= msg_spy_find_next_msg(WM_IME_COMPOSITION
, &idx
);
1757 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1759 msg_spy_flush_msgs();
1761 lpIMC
= ImmLockIMC(imc
);
1762 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1763 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1764 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1765 lpTransMsg
->message
= WM_IME_ENDCOMPOSITION
;
1766 lpTransMsg
->wParam
= 0;
1767 lpTransMsg
->lParam
= 0;
1768 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1769 lpIMC
->dwNumMsgBuf
++;
1771 ImmGenerateMessage(imc
);
1775 msg
= msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION
, &idx
);
1776 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1778 msg_spy_flush_msgs();
1780 ImmSetOpenStatus(imc
, FALSE
);
1781 ImmReleaseContext(hwnd
, imc
);
1782 DestroyWindow(hwnd
);
1785 static LRESULT CALLBACK
processkey_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
1788 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1791 static void test_ime_processkey(void)
1795 HANDLE hInstance
= GetModuleHandleW(NULL
);
1796 TEST_INPUT inputs
[2];
1801 wclass
.lpszClassName
= L
"ProcessKeyTestClass";
1802 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1803 wclass
.lpfnWndProc
= processkey_wnd_proc
;
1804 wclass
.hInstance
= hInstance
;
1805 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
1806 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
1807 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1808 wclass
.lpszMenuName
= 0;
1809 wclass
.cbClsExtra
= 0;
1810 wclass
.cbWndExtra
= 0;
1811 if(!RegisterClassW(&wclass
)){
1812 win_skip("Failed to register window.\n");
1816 /* create the test window that will receive the keystrokes */
1817 hWndTest
= CreateWindowW(wclass
.lpszClassName
, L
"ProcessKey",
1818 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
1819 NULL
, NULL
, hInstance
, NULL
);
1821 ShowWindow(hWndTest
, SW_SHOW
);
1822 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
1823 SetForegroundWindow(hWndTest
);
1824 UpdateWindow(hWndTest
);
1826 imc
= ImmGetContext(hWndTest
);
1829 win_skip("IME not supported\n");
1830 DestroyWindow(hWndTest
);
1834 rc
= ImmSetOpenStatus(imc
, TRUE
);
1837 win_skip("Unable to open IME\n");
1838 ImmReleaseContext(hWndTest
, imc
);
1839 DestroyWindow(hWndTest
);
1843 /* flush pending messages */
1844 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
1848 /* init input data that never changes */
1849 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
1850 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
1851 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
1853 /* Pressing a key */
1854 inputs
[0].u
.ki
.wVk
= 0x41;
1855 inputs
[0].u
.ki
.wScan
= 0x1e;
1856 inputs
[0].u
.ki
.dwFlags
= 0x0;
1858 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1860 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
1861 if(msg
.message
!= WM_KEYDOWN
)
1862 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1865 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
1866 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1867 if(msg
.wParam
== VK_PROCESSKEY
)
1868 trace("ProcessKey was correctly found\n");
1870 TranslateMessage(&msg
);
1871 /* test calling TranslateMessage multiple times */
1872 TranslateMessage(&msg
);
1873 DispatchMessageW(&msg
);
1876 inputs
[0].u
.ki
.wVk
= 0x41;
1877 inputs
[0].u
.ki
.wScan
= 0x1e;
1878 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1880 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1882 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
1883 if(msg
.message
!= WM_KEYUP
)
1884 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1887 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
1888 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1889 ok(msg
.wParam
!= VK_PROCESSKEY
,"ProcessKey should still not be Found\n");
1891 TranslateMessage(&msg
);
1892 DispatchMessageW(&msg
);
1895 ImmReleaseContext(hWndTest
, imc
);
1896 ImmSetOpenStatus(imc
, FALSE
);
1897 DestroyWindow(hWndTest
);
1900 static void test_InvalidIMC(void)
1903 HIMC imc_null
= 0x00000000;
1904 HIMC imc_bad
= (HIMC
)0xdeadcafe;
1906 HIMC imc1
, imc2
, oldimc
;
1914 memset(&lf
, 0, sizeof(lf
));
1916 imc_destroy
= ImmCreateContext();
1917 ret
= ImmDestroyContext(imc_destroy
);
1918 ok(ret
== TRUE
, "Destroy an IMC should success!\n");
1920 /* Test associating destroyed imc */
1921 imc1
= ImmGetContext(hwnd
);
1922 SetLastError(0xdeadbeef);
1923 oldimc
= ImmAssociateContext(hwnd
, imc_destroy
);
1924 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
1925 ret
= GetLastError();
1926 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1927 imc2
= ImmGetContext(hwnd
);
1928 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
1930 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
1931 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
1932 r
= ImmSetActiveContext(hwnd
, imc_destroy
, TRUE
);
1933 ok(!r
, "ImmSetActiveContext succeeded\n");
1934 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1935 r
= ImmSetActiveContext(hwnd
, imc_destroy
, FALSE
);
1936 ok(r
, "ImmSetActiveContext failed\n");
1937 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1938 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
1939 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
1941 /* Test associating NULL imc, which is different from an invalid imc */
1942 oldimc
= ImmAssociateContext(hwnd
, imc_null
);
1943 ok(oldimc
!= NULL
, "Associating to NULL imc should success!\n");
1944 imc2
= ImmGetContext(hwnd
);
1945 ok(!imc2
, "expect NULL, returned %p\n", imc2
);
1946 oldimc
= ImmAssociateContext(hwnd
, imc1
);
1947 ok(!oldimc
, "expect NULL, returned %p\n", oldimc
);
1948 imc2
= ImmGetContext(hwnd
);
1949 ok(imc2
== imc1
, "imc should not changed! imc2 %p, imc1 %p\n", imc2
, imc1
);
1951 /* Test associating invalid imc */
1952 imc1
= ImmGetContext(hwnd
);
1953 SetLastError(0xdeadbeef);
1954 oldimc
= ImmAssociateContext(hwnd
, imc_bad
);
1955 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
1956 ret
= GetLastError();
1957 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1958 imc2
= ImmGetContext(hwnd
);
1959 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
1962 /* Test ImmGetCandidateListA */
1963 SetLastError(0xdeadbeef);
1964 ret
= ImmGetCandidateListA(imc_bad
, 0, NULL
, 0);
1965 ok(ret
== 0, "Bad IME should return 0\n");
1966 ret
= GetLastError();
1967 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1968 SetLastError(0xdeadbeef);
1969 ret
= ImmGetCandidateListA(imc_null
, 0, NULL
, 0);
1970 ok(ret
== 0, "NULL IME should return 0\n");
1971 ret
= GetLastError();
1972 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
1973 SetLastError(0xdeadbeef);
1974 ret
= ImmGetCandidateListA(imc_destroy
, 0, NULL
, 0);
1975 ok(ret
== 0, "Destroyed IME should return 0\n");
1976 ret
= GetLastError();
1977 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1979 /* Test ImmGetCandidateListCountA*/
1980 SetLastError(0xdeadbeef);
1981 ret
= ImmGetCandidateListCountA(imc_bad
,&count
);
1982 ok(ret
== 0, "Bad IME should return 0\n");
1983 ret
= GetLastError();
1984 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1985 SetLastError(0xdeadbeef);
1986 ret
= ImmGetCandidateListCountA(imc_null
,&count
);
1987 ok(ret
== 0, "NULL IME should return 0\n");
1988 ret
= GetLastError();
1989 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
1990 SetLastError(0xdeadbeef);
1991 ret
= ImmGetCandidateListCountA(imc_destroy
,&count
);
1992 ok(ret
== 0, "Destroyed IME should return 0\n");
1993 ret
= GetLastError();
1994 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
1996 /* Test ImmGetCandidateWindow */
1997 SetLastError(0xdeadbeef);
1998 ret
= ImmGetCandidateWindow(imc_bad
, 0, (LPCANDIDATEFORM
)buffer
);
1999 ok(ret
== 0, "Bad IME should return 0\n");
2000 ret
= GetLastError();
2001 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2002 SetLastError(0xdeadbeef);
2003 ret
= ImmGetCandidateWindow(imc_null
, 0, (LPCANDIDATEFORM
)buffer
);
2004 ok(ret
== 0, "NULL IME should return 0\n");
2005 ret
= GetLastError();
2006 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2007 SetLastError(0xdeadbeef);
2008 ret
= ImmGetCandidateWindow(imc_destroy
, 0, (LPCANDIDATEFORM
)buffer
);
2009 ok(ret
== 0, "Destroyed IME should return 0\n");
2010 ret
= GetLastError();
2011 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2013 /* Test ImmGetCompositionFontA */
2014 SetLastError(0xdeadbeef);
2015 ret
= ImmGetCompositionFontA(imc_bad
, (LPLOGFONTA
)buffer
);
2016 ok(ret
== 0, "Bad IME should return 0\n");
2017 ret
= GetLastError();
2018 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2019 SetLastError(0xdeadbeef);
2020 ret
= ImmGetCompositionFontA(imc_null
, (LPLOGFONTA
)buffer
);
2021 ok(ret
== 0, "NULL IME should return 0\n");
2022 ret
= GetLastError();
2023 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2024 SetLastError(0xdeadbeef);
2025 ret
= ImmGetCompositionFontA(imc_destroy
, (LPLOGFONTA
)buffer
);
2026 ok(ret
== 0, "Destroyed IME should return 0\n");
2027 ret
= GetLastError();
2028 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2030 /* Test ImmGetCompositionWindow */
2031 SetLastError(0xdeadbeef);
2032 ret
= ImmGetCompositionWindow(imc_bad
, (LPCOMPOSITIONFORM
)buffer
);
2033 ok(ret
== 0, "Bad IME should return 0\n");
2034 ret
= GetLastError();
2035 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2036 SetLastError(0xdeadbeef);
2037 ret
= ImmGetCompositionWindow(imc_null
, (LPCOMPOSITIONFORM
)buffer
);
2038 ok(ret
== 0, "NULL IME should return 0\n");
2039 ret
= GetLastError();
2040 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2041 SetLastError(0xdeadbeef);
2042 ret
= ImmGetCompositionWindow(imc_destroy
, (LPCOMPOSITIONFORM
)buffer
);
2043 ok(ret
== 0, "Destroyed IME should return 0\n");
2044 ret
= GetLastError();
2045 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2047 /* Test ImmGetCompositionStringA */
2048 SetLastError(0xdeadbeef);
2049 ret
= ImmGetCompositionStringA(imc_bad
, GCS_COMPSTR
, NULL
, 0);
2050 ok(ret
== 0, "Bad IME should return 0\n");
2051 ret
= GetLastError();
2052 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2053 SetLastError(0xdeadbeef);
2054 ret
= ImmGetCompositionStringA(imc_null
, GCS_COMPSTR
, NULL
, 0);
2055 ok(ret
== 0, "NULL IME should return 0\n");
2056 ret
= GetLastError();
2057 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2058 SetLastError(0xdeadbeef);
2059 ret
= ImmGetCompositionStringA(imc_destroy
, GCS_COMPSTR
, NULL
, 0);
2060 ok(ret
== 0, "Destroyed IME should return 0\n");
2061 ret
= GetLastError();
2062 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2064 /* Test ImmSetOpenStatus */
2065 SetLastError(0xdeadbeef);
2066 ret
= ImmSetOpenStatus(imc_bad
, 1);
2067 ok(ret
== 0, "Bad IME should return 0\n");
2068 ret
= GetLastError();
2069 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2070 SetLastError(0xdeadbeef);
2071 ret
= ImmSetOpenStatus(imc_null
, 1);
2072 ok(ret
== 0, "NULL IME should return 0\n");
2073 ret
= GetLastError();
2074 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2075 SetLastError(0xdeadbeef);
2076 ret
= ImmSetOpenStatus(imc_destroy
, 1);
2077 ok(ret
== 0, "Destroyed IME should return 0\n");
2078 ret
= GetLastError();
2079 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2081 /* Test ImmGetOpenStatus */
2082 SetLastError(0xdeadbeef);
2083 ret
= ImmGetOpenStatus(imc_bad
);
2084 ok(ret
== 0, "Bad IME should return 0\n");
2085 ret
= GetLastError();
2086 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2087 SetLastError(0xdeadbeef);
2088 ret
= ImmGetOpenStatus(imc_null
);
2089 ok(ret
== 0, "NULL IME should return 0\n");
2090 ret
= GetLastError();
2091 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2092 SetLastError(0xdeadbeef);
2093 ret
= ImmGetOpenStatus(imc_destroy
);
2094 ok(ret
== 0, "Destroyed IME should return 0\n");
2095 ret
= GetLastError();
2096 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2098 /* Test ImmGetStatusWindowPos */
2099 SetLastError(0xdeadbeef);
2100 ret
= ImmGetStatusWindowPos(imc_bad
, NULL
);
2101 ok(ret
== 0, "Bad IME should return 0\n");
2102 ret
= GetLastError();
2103 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2104 SetLastError(0xdeadbeef);
2105 ret
= ImmGetStatusWindowPos(imc_null
, NULL
);
2106 ok(ret
== 0, "NULL IME should return 0\n");
2107 ret
= GetLastError();
2108 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2109 SetLastError(0xdeadbeef);
2110 ret
= ImmGetStatusWindowPos(imc_destroy
, NULL
);
2111 ok(ret
== 0, "Destroyed IME should return 0\n");
2112 ret
= GetLastError();
2113 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2115 /* Test ImmRequestMessageA */
2116 SetLastError(0xdeadbeef);
2117 ret
= ImmRequestMessageA(imc_bad
, WM_CHAR
, 0);
2118 ok(ret
== 0, "Bad IME should return 0\n");
2119 ret
= GetLastError();
2120 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2121 SetLastError(0xdeadbeef);
2122 ret
= ImmRequestMessageA(imc_null
, WM_CHAR
, 0);
2123 ok(ret
== 0, "NULL IME should return 0\n");
2124 ret
= GetLastError();
2125 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2126 SetLastError(0xdeadbeef);
2127 ret
= ImmRequestMessageA(imc_destroy
, WM_CHAR
, 0);
2128 ok(ret
== 0, "Destroyed IME should return 0\n");
2129 ret
= GetLastError();
2130 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2132 /* Test ImmSetCompositionFontA */
2133 SetLastError(0xdeadbeef);
2134 ret
= ImmSetCompositionFontA(imc_bad
, &lf
);
2135 ok(ret
== 0, "Bad IME should return 0\n");
2136 ret
= GetLastError();
2137 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2138 SetLastError(0xdeadbeef);
2139 ret
= ImmSetCompositionFontA(imc_null
, &lf
);
2140 ok(ret
== 0, "NULL IME should return 0\n");
2141 ret
= GetLastError();
2142 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2143 SetLastError(0xdeadbeef);
2144 ret
= ImmSetCompositionFontA(imc_destroy
, &lf
);
2145 ok(ret
== 0, "Destroyed IME should return 0\n");
2146 ret
= GetLastError();
2147 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2149 /* Test ImmSetCompositionWindow */
2150 SetLastError(0xdeadbeef);
2151 ret
= ImmSetCompositionWindow(imc_bad
, NULL
);
2152 ok(ret
== 0, "Bad IME should return 0\n");
2153 ret
= GetLastError();
2154 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2155 SetLastError(0xdeadbeef);
2156 ret
= ImmSetCompositionWindow(imc_null
, NULL
);
2157 ok(ret
== 0, "NULL IME should return 0\n");
2158 ret
= GetLastError();
2159 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2160 SetLastError(0xdeadbeef);
2161 ret
= ImmSetCompositionWindow(imc_destroy
, NULL
);
2162 ok(ret
== 0, "Destroyed IME should return 0\n");
2163 ret
= GetLastError();
2164 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2166 /* Test ImmSetConversionStatus */
2167 SetLastError(0xdeadbeef);
2168 ret
= ImmSetConversionStatus(imc_bad
, 0, 0);
2169 ok(ret
== 0, "Bad IME should return 0\n");
2170 ret
= GetLastError();
2171 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2172 SetLastError(0xdeadbeef);
2173 ret
= ImmSetConversionStatus(imc_null
, 0, 0);
2174 ok(ret
== 0, "NULL IME should return 0\n");
2175 ret
= GetLastError();
2176 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2177 SetLastError(0xdeadbeef);
2178 ret
= ImmSetConversionStatus(imc_destroy
, 0, 0);
2179 ok(ret
== 0, "Destroyed IME should return 0\n");
2180 ret
= GetLastError();
2181 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2183 /* Test ImmSetStatusWindowPos */
2184 SetLastError(0xdeadbeef);
2185 ret
= ImmSetStatusWindowPos(imc_bad
, 0);
2186 ok(ret
== 0, "Bad IME should return 0\n");
2187 ret
= GetLastError();
2188 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2189 SetLastError(0xdeadbeef);
2190 ret
= ImmSetStatusWindowPos(imc_null
, 0);
2191 ok(ret
== 0, "NULL IME should return 0\n");
2192 ret
= GetLastError();
2193 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2194 SetLastError(0xdeadbeef);
2195 ret
= ImmSetStatusWindowPos(imc_destroy
, 0);
2196 ok(ret
== 0, "Destroyed IME should return 0\n");
2197 ret
= GetLastError();
2198 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2200 /* Test ImmGetImeMenuItemsA */
2201 SetLastError(0xdeadbeef);
2202 ret
= ImmGetImeMenuItemsA(imc_bad
, 0, 0, NULL
, NULL
, 0);
2203 ok(ret
== 0, "Bad IME should return 0\n");
2204 ret
= GetLastError();
2205 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2206 SetLastError(0xdeadbeef);
2207 ret
= ImmGetImeMenuItemsA(imc_null
, 0, 0, NULL
, NULL
, 0);
2208 ok(ret
== 0, "NULL IME should return 0\n");
2209 ret
= GetLastError();
2210 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2211 SetLastError(0xdeadbeef);
2212 ret
= ImmGetImeMenuItemsA(imc_destroy
, 0, 0, NULL
, NULL
, 0);
2213 ok(ret
== 0, "Destroyed IME should return 0\n");
2214 ret
= GetLastError();
2215 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2217 /* Test ImmLockIMC */
2218 SetLastError(0xdeadbeef);
2219 ic
= ImmLockIMC(imc_bad
);
2220 ok(ic
== 0, "Bad IME should return 0\n");
2221 ret
= GetLastError();
2222 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2223 SetLastError(0xdeadbeef);
2224 ic
= ImmLockIMC(imc_null
);
2225 ok(ic
== 0, "NULL IME should return 0\n");
2226 ret
= GetLastError();
2227 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2228 SetLastError(0xdeadbeef);
2229 ic
= ImmLockIMC(imc_destroy
);
2230 ok(ic
== 0, "Destroyed IME should return 0\n");
2231 ret
= GetLastError();
2232 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2234 /* Test ImmUnlockIMC */
2235 SetLastError(0xdeadbeef);
2236 ret
= ImmUnlockIMC(imc_bad
);
2237 ok(ret
== 0, "Bad IME should return 0\n");
2238 ret
= GetLastError();
2239 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2240 SetLastError(0xdeadbeef);
2241 ret
= ImmUnlockIMC(imc_null
);
2242 ok(ret
== 0, "NULL IME should return 0\n");
2243 ret
= GetLastError();
2244 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2245 SetLastError(0xdeadbeef);
2246 ret
= ImmUnlockIMC(imc_destroy
);
2247 ok(ret
== 0, "Destroyed IME should return 0\n");
2248 ret
= GetLastError();
2249 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2251 /* Test ImmGenerateMessage */
2252 SetLastError(0xdeadbeef);
2253 ret
= ImmGenerateMessage(imc_bad
);
2254 ok(ret
== 0, "Bad IME should return 0\n");
2255 ret
= GetLastError();
2256 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2257 SetLastError(0xdeadbeef);
2258 ret
= ImmGenerateMessage(imc_null
);
2259 ok(ret
== 0, "NULL IME should return 0\n");
2260 ret
= GetLastError();
2261 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2262 SetLastError(0xdeadbeef);
2263 ret
= ImmGenerateMessage(imc_destroy
);
2264 ok(ret
== 0, "Destroyed IME should return 0\n");
2265 ret
= GetLastError();
2266 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2269 #define test_apttype(apttype) _test_apttype(apttype, __LINE__)
2270 static void _test_apttype(APTTYPE apttype
, unsigned int line
)
2272 APTTYPEQUALIFIER qualifier
;
2273 HRESULT hr
, hr_expected
;
2276 hr
= CoGetApartmentType(&type
, &qualifier
);
2277 hr_expected
= (apttype
== -1 ? CO_E_NOTINITIALIZED
: S_OK
);
2278 ok_(__FILE__
, line
)(hr
== hr_expected
, "CoGetApartmentType returned %lx\n", hr
);
2282 ok_(__FILE__
, line
)(type
== apttype
, "type %x\n", type
);
2283 ok_(__FILE__
, line
)(!qualifier
, "qualifier %x\n", qualifier
);
2286 static DWORD WINAPI
com_initialization_thread(void *arg
)
2292 ImmDisableIME(GetCurrentThreadId());
2293 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2294 ok(r
, "ImmSetActiveContext failed\n");
2295 test_apttype(APTTYPE_MAINSTA
);
2296 hr
= CoInitialize(NULL
);
2297 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2301 /* Changes IMM behavior so it no longer initialized COM */
2302 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2303 ok(r
, "ImmSetActiveContext failed\n");
2304 test_apttype(APTTYPE_MAINSTA
);
2305 hr
= CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
2306 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2307 test_apttype(APTTYPE_MTA
);
2310 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2311 ok(r
, "ImmSetActiveContext failed\n");
2316 static void test_com_initialization(void)
2318 APTTYPEQUALIFIER qualifier
;
2325 thread
= CreateThread(NULL
, 0, com_initialization_thread
, NULL
, 0, NULL
);
2326 ok(thread
!= NULL
, "CreateThread failed\n");
2327 WaitForSingleObject(thread
, INFINITE
);
2328 CloseHandle(thread
);
2331 r
= ImmSetActiveContext(NULL
, (HIMC
)0xdeadbeef, TRUE
);
2332 ok(!r
, "ImmSetActiveContext succeeded\n");
2335 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2336 ok(r
, "ImmSetActiveContext failed\n");
2337 test_apttype(APTTYPE_MAINSTA
);
2339 /* Force default IME window destruction */
2340 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2341 ok(wnd
!= NULL
, "CreateWindow failed\n");
2345 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2346 ok(r
, "ImmSetActiveContext failed\n");
2347 test_apttype(APTTYPE_MAINSTA
);
2348 hr
= CoInitialize(NULL
);
2349 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2353 /* Test with default IME window created */
2354 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2355 ok(wnd
!= NULL
, "CreateWindow failed\n");
2357 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2358 ok(r
, "ImmSetActiveContext failed\n");
2359 test_apttype(APTTYPE_MAINSTA
);
2360 hr
= CoInitialize(NULL
);
2361 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2363 test_apttype(APTTYPE_MAINSTA
);
2367 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2368 ok(wnd
!= NULL
, "CreateWindow failed\n");
2369 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2371 hr
= CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
2372 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2373 test_apttype(APTTYPE_MTA
);
2376 hr
= CoGetApartmentType(&type
, &qualifier
);
2377 ok(hr
== CO_E_NOTINITIALIZED
|| broken(hr
== S_OK
) /* w10v22H2 */,
2378 "CoGetApartmentType returned %#lx\n", hr
);
2379 test_apttype(hr
== S_OK
? APTTYPE_MTA
: -1);
2381 wnd
= CreateWindowA("static", "static", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, 0);
2382 ok(wnd
!= NULL
, "CreateWindow failed\n");
2383 test_apttype(hr
== S_OK
? APTTYPE_MTA
: -1);
2384 ShowWindow(wnd
, SW_SHOW
);
2385 test_apttype(hr
== S_OK
? APTTYPE_MTA
: APTTYPE_MAINSTA
);
2390 static DWORD WINAPI
disable_ime_thread(void *arg
)
2396 h
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2397 ok(h
!= NULL
, "CreateWindow failed\n");
2398 def
= ImmGetDefaultIMEWnd(h
);
2399 ok(def
!= NULL
, "ImmGetDefaultIMEWnd returned NULL\n");
2401 r
= ImmDisableIME(arg
? GetCurrentThreadId() : 0);
2402 ok(r
, "ImmDisableIME failed\n");
2406 def
= ImmGetDefaultIMEWnd(h
);
2407 todo_wine
ok(def
!= NULL
, "ImmGetDefaultIMEWnd returned NULL\n");
2408 while(PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
2409 DispatchMessageA(&msg
);
2411 def
= ImmGetDefaultIMEWnd(h
);
2412 ok(!def
, "ImmGetDefaultIMEWnd returned %p\n", def
);
2416 static DWORD WINAPI
check_not_disabled_ime_thread(void *arg
)
2420 WaitForSingleObject(arg
, INFINITE
);
2421 hwnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2422 ok(hwnd
!= NULL
, "CreateWindow failed\n");
2423 def
= ImmGetDefaultIMEWnd(hwnd
);
2424 ok(def
!= NULL
, "ImmGetDefaultIMEWnd returned %p\n", def
);
2428 static DWORD WINAPI
disable_ime_process(void *arg
)
2430 BOOL r
= ImmDisableIME(-1);
2431 ok(r
, "ImmDisableIME failed\n");
2435 static void test_ImmDisableIME(void)
2437 HANDLE thread
, event
;
2442 def
= ImmGetDefaultIMEWnd(hwnd
);
2443 ok(def
!= NULL
, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n");
2445 event
= CreateEventW(NULL
, TRUE
, FALSE
, FALSE
);
2446 thread
= CreateThread(NULL
, 0, check_not_disabled_ime_thread
, event
, 0, &tid
);
2447 ok(thread
!= NULL
, "CreateThread failed\n");
2448 r
= ImmDisableIME(tid
);
2449 ok(!r
, "ImmDisableIME(tid) succeeded\n");
2451 WaitForSingleObject(thread
, INFINITE
);
2452 CloseHandle(thread
);
2455 thread
= CreateThread(NULL
, 0, disable_ime_thread
, 0, 0, NULL
);
2456 ok(thread
!= NULL
, "CreateThread failed\n");
2457 WaitForSingleObject(thread
, INFINITE
);
2458 CloseHandle(thread
);
2460 thread
= CreateThread(NULL
, 0, disable_ime_thread
, (void*)1, 0, NULL
);
2461 ok(thread
!= NULL
, "CreateThread failed\n");
2462 WaitForSingleObject(thread
, INFINITE
);
2463 CloseHandle(thread
);
2465 msg_spy_pump_msg_queue();
2466 thread
= CreateThread(NULL
, 0, disable_ime_process
, 0, 0, NULL
);
2467 ok(thread
!= NULL
, "CreateThread failed\n");
2468 WaitForSingleObject(thread
, INFINITE
);
2469 CloseHandle(thread
);
2471 ok(IsWindow(def
), "not a window\n");
2472 def2
= ImmGetDefaultIMEWnd(hwnd
);
2473 ok(def2
== def
, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2
);
2474 ok(IsWindow(def
), "not a window\n");
2475 msg_spy_pump_msg_queue();
2476 ok(!IsWindow(def
), "window is still valid\n");
2477 def
= ImmGetDefaultIMEWnd(hwnd
);
2478 ok(!def
, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def
);
2480 r
= ImmDisableIME(-1);
2481 ok(r
, "ImmDisableIME(-1) failed\n");
2482 def
= ImmGetDefaultIMEWnd(hwnd
);
2483 ok(!def
, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def
);
2486 #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ )
2488 static BOOL todo_ImeInquire
;
2489 DEFINE_EXPECT( ImeInquire
);
2490 static BOOL todo_ImeDestroy
;
2491 DEFINE_EXPECT( ImeDestroy
);
2492 DEFINE_EXPECT( ImeEscape
);
2493 DEFINE_EXPECT( ImeEnumRegisterWord
);
2494 DEFINE_EXPECT( ImeRegisterWord
);
2495 DEFINE_EXPECT( ImeGetRegisterWordStyle
);
2496 DEFINE_EXPECT( ImeUnregisterWord
);
2497 static BOOL todo_IME_DLL_PROCESS_ATTACH
;
2498 DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH
);
2499 static BOOL todo_IME_DLL_PROCESS_DETACH
;
2500 DEFINE_EXPECT( IME_DLL_PROCESS_DETACH
);
2502 static IMEINFO ime_info
;
2503 static UINT ime_count
;
2504 static WCHAR ime_path
[MAX_PATH
];
2505 static HIMC default_himc
;
2506 static HKL default_hkl
;
2507 static HKL expect_ime
= (HKL
)(int)0xe020047f;
2521 enum ime_function func
;
2550 struct ime_call empty_sequence
[] = {{0}};
2551 static struct ime_call ime_calls
[1024];
2552 static ULONG ime_call_count
;
2554 #define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b )
2555 static int ok_call_( const char *file
, int line
, const struct ime_call
*expected
, const struct ime_call
*received
)
2559 if ((ret
= expected
->func
- received
->func
)) goto done
;
2560 /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */
2561 if (expected
->flaky_himc
&& (ret
= !!(UINT_PTR
)expected
->himc
- !!(UINT_PTR
)received
->himc
)) goto done
;
2562 if (!expected
->flaky_himc
&& (ret
= (UINT_PTR
)expected
->himc
- (UINT_PTR
)received
->himc
)) goto done
;
2563 if ((ret
= (UINT
)(UINT_PTR
)expected
->hkl
- (UINT
)(UINT_PTR
)received
->hkl
)) goto done
;
2564 switch (expected
->func
)
2567 if ((ret
= expected
->select
- received
->select
)) goto done
;
2570 if ((ret
= expected
->notify
.action
- received
->notify
.action
)) goto done
;
2571 if ((ret
= expected
->notify
.index
- received
->notify
.index
)) goto done
;
2572 if ((ret
= expected
->notify
.value
- received
->notify
.value
)) goto done
;
2574 case IME_PROCESS_KEY
:
2575 if ((ret
= expected
->process_key
.vkey
- received
->process_key
.vkey
)) goto done
;
2576 if ((ret
= expected
->process_key
.key_data
- received
->process_key
.key_data
)) goto done
;
2579 if ((ret
= expected
->message
.msg
- received
->message
.msg
)) goto done
;
2580 if ((ret
= (expected
->message
.wparam
- received
->message
.wparam
))) goto done
;
2581 if ((ret
= (expected
->message
.lparam
- received
->message
.lparam
))) goto done
;
2586 if (ret
&& broken( expected
->broken
)) return ret
;
2588 switch (received
->func
)
2591 todo_wine_if( expected
->todo
)
2592 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_SELECT select %u\n", received
->hkl
, received
->himc
, received
->select
);
2595 todo_wine_if( expected
->todo
)
2596 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n",
2597 received
->hkl
, received
->himc
, received
->notify
.action
, received
->notify
.index
,
2598 received
->notify
.value
);
2600 case IME_PROCESS_KEY
:
2601 todo_wine_if( expected
->todo
)
2602 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n",
2603 received
->hkl
, received
->himc
, received
->process_key
.vkey
, received
->process_key
.key_data
);
2606 todo_wine_if( expected
->todo
)
2607 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received
->hkl
,
2608 received
->himc
, received
->message
.msg
, received
->message
.wparam
, received
->message
.lparam
);
2612 switch (expected
->func
)
2615 todo_wine_if( expected
->todo
)
2616 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_SELECT select %u\n", expected
->hkl
, expected
->himc
, expected
->select
);
2619 todo_wine_if( expected
->todo
)
2620 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n",
2621 expected
->hkl
, expected
->himc
, expected
->notify
.action
, expected
->notify
.index
,
2622 expected
->notify
.value
);
2624 case IME_PROCESS_KEY
:
2625 todo_wine_if( expected
->todo
)
2626 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n",
2627 expected
->hkl
, expected
->himc
, expected
->process_key
.vkey
, expected
->process_key
.key_data
);
2630 todo_wine_if( expected
->todo
)
2631 ok_(file
, line
)( !ret
, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected
->hkl
,
2632 expected
->himc
, expected
->message
.msg
, expected
->message
.wparam
, expected
->message
.lparam
);
2639 #define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a )
2640 static void ok_seq_( const char *file
, int line
, const struct ime_call
*expected
, const char *context
)
2642 const struct ime_call
*received
= ime_calls
;
2645 while (expected
->func
|| received
->func
)
2647 winetest_push_context( "%u%s%s", i
++, !expected
->func
? " (spurious)" : "",
2648 !received
->func
? " (missing)" : "" );
2649 ret
= ok_call_( file
, line
, expected
, received
);
2650 if (ret
&& expected
->todo
&& !strcmp( winetest_platform
, "wine" ))
2652 else if (ret
&& broken(expected
->broken
))
2656 if (expected
->func
) expected
++;
2657 if (received
->func
) received
++;
2659 winetest_pop_context();
2662 memset( ime_calls
, 0, sizeof(ime_calls
) );
2666 static BOOL
ignore_message( UINT msg
)
2670 case WM_IME_STARTCOMPOSITION
:
2671 case WM_IME_ENDCOMPOSITION
:
2672 case WM_IME_COMPOSITION
:
2673 case WM_IME_SETCONTEXT
:
2675 case WM_IME_CONTROL
:
2676 case WM_IME_COMPOSITIONFULL
:
2680 case WM_IME_REQUEST
:
2681 case WM_IME_KEYDOWN
:
2689 static LRESULT CALLBACK
ime_ui_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
2691 struct ime_call call
=
2693 .hkl
= GetKeyboardLayout( 0 ), .himc
= (HIMC
)GetWindowLongPtrW( hwnd
, IMMGWL_IMC
),
2694 .func
= MSG_IME_UI
, .message
= {.msg
= msg
, .wparam
= wparam
, .lparam
= lparam
}
2698 ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
2700 if (ignore_message( msg
)) return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
2702 ptr
= GetWindowLongPtrW( hwnd
, IMMGWL_PRIVATE
);
2703 ok( !ptr
, "got IMMGWL_PRIVATE %#Ix\n", ptr
);
2705 ime_calls
[ime_call_count
++] = call
;
2706 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
2709 static WNDCLASSEXW ime_ui_class
=
2711 .cbSize
= sizeof(WNDCLASSEXW
),
2713 .lpfnWndProc
= ime_ui_window_proc
,
2714 .cbWndExtra
= 2 * sizeof(LONG_PTR
),
2715 .lpszClassName
= L
"WineTestIME",
2718 static BOOL WINAPI
ime_ImeConfigure( HKL hkl
, HWND hwnd
, DWORD mode
, void *data
)
2720 ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl
, hwnd
, mode
, data
);
2721 ok( 0, "unexpected call\n" );
2725 static DWORD WINAPI
ime_ImeConversionList( HIMC himc
, const WCHAR
*source
, CANDIDATELIST
*dest
,
2726 DWORD dest_len
, UINT flag
)
2728 ime_trace( "himc %p, source %s, dest %p, dest_len %lu, flag %#x\n",
2729 himc
, debugstr_w(source
), dest
, dest_len
, flag
);
2730 ok( 0, "unexpected call\n" );
2734 static BOOL WINAPI
ime_ImeDestroy( UINT force
)
2736 ime_trace( "force %u\n", force
);
2738 todo_wine_if( todo_ImeDestroy
)
2739 CHECK_EXPECT( ImeDestroy
);
2741 ok( !force
, "got force %u\n", force
);
2746 static UINT WINAPI
ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc
, const WCHAR
*reading
, DWORD style
,
2747 const WCHAR
*string
, void *data
)
2749 ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n",
2750 proc
, debugstr_w(reading
), style
, debugstr_w(string
), data
);
2752 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
2753 CHECK_EXPECT( ImeEnumRegisterWord
);
2757 ok_eq( 0, reading
, const void *, "%p" );
2758 ok_eq( 0, string
, const void *, "%p" );
2760 else if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
2762 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
2763 ok_wcs( L
"Reading", reading
);
2764 ok_wcs( L
"String", string
);
2768 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
2769 ok_str( "Reading", (char *)reading
);
2770 ok_str( "String", (char *)string
);
2773 if (style
) return proc( reading
, style
, string
, data
);
2777 static LRESULT WINAPI
ime_ImeEscape( HIMC himc
, UINT escape
, void *data
)
2779 ime_trace( "himc %p, escape %#x, data %p\n", himc
, escape
, data
);
2781 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
2782 CHECK_EXPECT( ImeEscape
);
2786 case IME_ESC_SET_EUDC_DICTIONARY
:
2787 if (!data
) return 4;
2788 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
2789 ok_wcs( L
"EscapeIme", data
);
2791 ok_str( "EscapeIme", data
);
2793 case IME_ESC_QUERY_SUPPORT
:
2794 case IME_ESC_SEQUENCE_TO_INTERNAL
:
2795 case IME_ESC_GET_EUDC_DICTIONARY
:
2796 case IME_ESC_MAX_KEY
:
2797 case IME_ESC_IME_NAME
:
2798 case IME_ESC_HANJA_MODE
:
2799 case IME_ESC_GETHELPFILENAME
:
2800 if (!data
) return 4;
2801 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
) wcscpy( data
, L
"ImeEscape" );
2802 else strcpy( data
, "ImeEscape" );
2806 ok_eq( 0xdeadbeef, escape
, UINT
, "%#x" );
2807 ok_eq( NULL
, data
, void *, "%p" );
2812 static DWORD WINAPI
ime_ImeGetImeMenuItems( HIMC himc
, DWORD flags
, DWORD type
, IMEMENUITEMINFOW
*parent
,
2813 IMEMENUITEMINFOW
*menu
, DWORD size
)
2815 ime_trace( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx\n",
2816 himc
, flags
, type
, parent
, menu
, size
);
2817 ok( 0, "unexpected call\n" );
2821 static UINT WINAPI
ime_ImeGetRegisterWordStyle( UINT item
, STYLEBUFW
*style
)
2823 ime_trace( "item %u, style %p\n", item
, style
);
2825 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
2826 CHECK_EXPECT( ImeGetRegisterWordStyle
);
2829 ok_eq( 16, item
, UINT
, "%u" );
2830 else if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
2832 STYLEBUFW
*styleW
= style
;
2833 styleW
->dwStyle
= 0xdeadbeef;
2834 wcscpy( styleW
->szDescription
, L
"StyleDescription" );
2838 STYLEBUFA
*styleA
= (STYLEBUFA
*)style
;
2839 styleA
->dwStyle
= 0xdeadbeef;
2840 strcpy( styleA
->szDescription
, "StyleDescription" );
2846 static BOOL WINAPI
ime_ImeInquire( IMEINFO
*info
, WCHAR
*ui_class
, DWORD flags
)
2848 ime_trace( "info %p, ui_class %p, flags %#lx\n", info
, ui_class
, flags
);
2850 todo_wine_if( todo_ImeInquire
)
2851 CHECK_EXPECT( ImeInquire
);
2853 ok( !!info
, "got info %p\n", info
);
2854 ok( !!ui_class
, "got ui_class %p\n", ui_class
);
2855 ok( !flags
, "got flags %#lx\n", flags
);
2859 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
2860 wcscpy( ui_class
, ime_ui_class
.lpszClassName
);
2862 WideCharToMultiByte( CP_ACP
, 0, ime_ui_class
.lpszClassName
, -1,
2863 (char *)ui_class
, 17, NULL
, NULL
);
2868 static BOOL WINAPI
ime_ImeProcessKey( HIMC himc
, UINT vkey
, LPARAM key_data
, BYTE
*key_state
)
2870 struct ime_call call
=
2872 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
2873 .func
= IME_PROCESS_KEY
, .process_key
= {.vkey
= vkey
, .key_data
= key_data
}
2875 ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n",
2876 himc
, vkey
, key_data
, key_state
);
2877 ime_calls
[ime_call_count
++] = call
;
2881 static BOOL WINAPI
ime_ImeRegisterWord( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
)
2883 ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading
), style
, debugstr_w(string
) );
2885 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
2886 CHECK_EXPECT( ImeRegisterWord
);
2888 if (style
) ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
2889 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
2891 if (reading
) ok_wcs( L
"Reading", reading
);
2892 if (string
) ok_wcs( L
"String", string
);
2896 if (reading
) ok_str( "Reading", (char *)reading
);
2897 if (string
) ok_str( "String", (char *)string
);
2903 static BOOL WINAPI
ime_ImeSelect( HIMC himc
, BOOL select
)
2905 struct ime_call call
=
2907 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
2908 .func
= IME_SELECT
, .select
= select
2910 ime_trace( "himc %p, select %d\n", himc
, select
);
2911 ime_calls
[ime_call_count
++] = call
;
2915 static BOOL WINAPI
ime_ImeSetActiveContext( HIMC himc
, BOOL flag
)
2917 ime_trace( "himc %p, flag %#x\n", himc
, flag
);
2918 ok( 0, "unexpected call\n" );
2922 static BOOL WINAPI
ime_ImeSetCompositionString( HIMC himc
, DWORD index
, const void *comp
, DWORD comp_len
,
2923 const void *read
, DWORD read_len
)
2925 ime_trace( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu\n",
2926 himc
, index
, comp
, comp_len
, read
, read_len
);
2927 ok( 0, "unexpected call\n" );
2931 static UINT WINAPI
ime_ImeToAsciiEx( UINT vkey
, UINT scan_code
, BYTE
*key_state
, TRANSMSGLIST
*msgs
, UINT state
, HIMC himc
)
2933 ime_trace( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p\n",
2934 vkey
, scan_code
, key_state
, msgs
, state
, himc
);
2938 static BOOL WINAPI
ime_ImeUnregisterWord( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
)
2940 ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading
), style
, debugstr_w(string
) );
2942 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
2943 CHECK_EXPECT( ImeUnregisterWord
);
2945 if (style
) ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
2946 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
2948 if (reading
) ok_wcs( L
"Reading", reading
);
2949 if (string
) ok_wcs( L
"String", string
);
2953 if (reading
) ok_str( "Reading", (char *)reading
);
2954 if (string
) ok_str( "String", (char *)string
);
2960 static BOOL WINAPI
ime_NotifyIME( HIMC himc
, DWORD action
, DWORD index
, DWORD value
)
2962 struct ime_call call
=
2964 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
2965 .func
= IME_NOTIFY
, .notify
= {.action
= action
, .index
= index
, .value
= value
}
2967 ime_trace( "himc %p, action %#lx, index %lu, value %lu\n", himc
, action
, index
, value
);
2968 ime_calls
[ime_call_count
++] = call
;
2972 static BOOL WINAPI
ime_DllMain( HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
2974 ime_trace( "instance %p, reason %lu, reserved %p.\n", instance
, reason
, reserved
);
2978 case DLL_PROCESS_ATTACH
:
2979 DisableThreadLibraryCalls( instance
);
2980 ime_ui_class
.hInstance
= instance
;
2981 RegisterClassExW( &ime_ui_class
);
2982 todo_wine_if(todo_IME_DLL_PROCESS_ATTACH
)
2983 CHECK_EXPECT( IME_DLL_PROCESS_ATTACH
);
2986 case DLL_PROCESS_DETACH
:
2987 UnregisterClassW( ime_ui_class
.lpszClassName
, instance
);
2988 todo_wine_if(todo_IME_DLL_PROCESS_DETACH
)
2989 CHECK_EXPECT( IME_DLL_PROCESS_DETACH
);
2996 static struct ime_functions ime_functions
=
2999 ime_ImeConversionList
,
3001 ime_ImeEnumRegisterWord
,
3003 ime_ImeGetImeMenuItems
,
3004 ime_ImeGetRegisterWordStyle
,
3007 ime_ImeRegisterWord
,
3009 ime_ImeSetActiveContext
,
3010 ime_ImeSetCompositionString
,
3012 ime_ImeUnregisterWord
,
3017 static HKL
ime_install(void)
3019 WCHAR buffer
[MAX_PATH
];
3025 /* IME module gets cached and won't reload from disk as soon as a window has
3026 * loaded it. To workaround the issue we load the module first as a DLL,
3027 * set its function pointers from the test, and later when the cached IME
3028 * gets loaded, read the function pointers from the separately loaded DLL.
3031 load_resource( L
"ime_wrapper.dll", buffer
);
3033 SetLastError( 0xdeadbeef );
3034 ret
= MoveFileW( buffer
, L
"c:\\windows\\system32\\winetest_ime.dll" );
3037 ok( GetLastError() == ERROR_ACCESS_DENIED
, "got error %lu\n", GetLastError() );
3038 win_skip( "Failed to copy DLL to system directory\n" );
3042 module
= LoadLibraryW( L
"c:\\windows\\system32\\winetest_ime.dll" );
3043 ok( !!module
, "LoadLibraryW failed, error %lu\n", GetLastError() );
3044 *(struct ime_functions
*)GetProcAddress( module
, "ime_functions" ) = ime_functions
;
3046 /* install the actual IME module, it will lookup the functions from the DLL */
3047 load_resource( L
"ime_wrapper.dll", buffer
);
3049 SetLastError( 0xdeadbeef );
3050 swprintf( ime_path
, ARRAY_SIZE(ime_path
), L
"c:\\windows\\system32\\wine%04x.ime", ime_count
++ );
3051 ret
= MoveFileW( buffer
, ime_path
);
3052 todo_wine_if( GetLastError() == ERROR_ALREADY_EXISTS
)
3053 ok( ret
|| broken( !ret
) /* sometimes still in use */,
3054 "MoveFileW failed, error %lu\n", GetLastError() );
3056 hkl
= ImmInstallIMEW( ime_path
, L
"WineTest IME" );
3057 ok( hkl
== expect_ime
, "ImmInstallIMEW returned %p, error %lu\n", hkl
, GetLastError() );
3059 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl
);
3060 ret
= RegOpenKeyW( HKEY_LOCAL_MACHINE
, buffer
, &hkey
);
3061 ok( !ret
, "RegOpenKeyW returned %#lx, error %lu\n", ret
, GetLastError() );
3063 len
= sizeof(buffer
);
3064 memset( buffer
, 0xcd, sizeof(buffer
) );
3065 ret
= RegQueryValueExW( hkey
, L
"Ime File", NULL
, NULL
, (BYTE
*)buffer
, &len
);
3066 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
3067 ok( !wcsicmp( buffer
, wcsrchr( ime_path
, '\\' ) + 1 ), "got Ime File %s\n", debugstr_w(buffer
) );
3069 len
= sizeof(buffer
);
3070 memset( buffer
, 0xcd, sizeof(buffer
) );
3071 ret
= RegQueryValueExW( hkey
, L
"Layout Text", NULL
, NULL
, (BYTE
*)buffer
, &len
);
3072 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
3073 ok( !wcscmp( buffer
, L
"WineTest IME" ), "got Layout Text %s\n", debugstr_w(buffer
) );
3075 len
= sizeof(buffer
);
3076 memset( buffer
, 0, sizeof(buffer
) );
3077 ret
= RegQueryValueExW( hkey
, L
"Layout File", NULL
, NULL
, (BYTE
*)buffer
, &len
);
3079 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
3081 ok( !wcscmp( buffer
, L
"kbdus.dll" ), "got Layout File %s\n", debugstr_w(buffer
) );
3083 ret
= RegCloseKey( hkey
);
3084 ok( !ret
, "RegCloseKey returned %#lx, error %lu\n", ret
, GetLastError() );
3089 static void ime_cleanup( HKL hkl
, BOOL free
)
3091 HMODULE module
= GetModuleHandleW( L
"winetest_ime.dll" );
3092 WCHAR buffer
[MAX_PATH
], value
[MAX_PATH
];
3093 DWORD i
, buffer_len
, value_len
, ret
;
3096 ret
= UnloadKeyboardLayout( hkl
);
3098 ok( ret
, "UnloadKeyboardLayout failed, error %lu\n", GetLastError() );
3100 if (free
) ok_ret( 1, ImmFreeLayout( hkl
) );
3102 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl
);
3103 ret
= RegDeleteKeyW( HKEY_LOCAL_MACHINE
, buffer
);
3104 ok( !ret
, "RegDeleteKeyW returned %#lx, error %lu\n", ret
, GetLastError() );
3106 ret
= RegOpenKeyW( HKEY_CURRENT_USER
, L
"Keyboard Layout\\Preload", &hkey
);
3107 ok( !ret
, "RegOpenKeyW returned %#lx, error %lu\n", ret
, GetLastError() );
3109 value_len
= ARRAY_SIZE(value
);
3110 buffer_len
= sizeof(buffer
);
3111 for (i
= 0; !RegEnumValueW( hkey
, i
, value
, &value_len
, NULL
, NULL
, (void *)buffer
, &buffer_len
); i
++)
3113 value_len
= ARRAY_SIZE(value
);
3114 buffer_len
= sizeof(buffer
);
3115 if (hkl
!= UlongToHandle( wcstoul( buffer
, NULL
, 16 ) )) continue;
3116 ret
= RegDeleteValueW( hkey
, value
);
3117 ok( !ret
, "RegDeleteValueW returned %#lx, error %lu\n", ret
, GetLastError() );
3120 ret
= RegCloseKey( hkey
);
3121 ok( !ret
, "RegCloseKey returned %#lx, error %lu\n", ret
, GetLastError() );
3123 ret
= DeleteFileW( ime_path
);
3124 todo_wine_if( GetLastError() == ERROR_ACCESS_DENIED
)
3125 ok( ret
|| broken( !ret
) /* sometimes still in use */,
3126 "DeleteFileW failed, error %lu\n", GetLastError() );
3128 ret
= FreeLibrary( module
);
3129 ok( ret
, "FreeLibrary failed, error %lu\n", GetLastError() );
3131 ret
= DeleteFileW( L
"c:\\windows\\system32\\winetest_ime.dll" );
3132 ok( ret
, "DeleteFileW failed, error %lu\n", GetLastError() );
3135 static BOOL CALLBACK
enum_get_context( HIMC himc
, LPARAM lparam
)
3137 ime_trace( "himc %p\n", himc
);
3138 *(HIMC
*)lparam
= himc
;
3142 static BOOL CALLBACK
enum_find_context( HIMC himc
, LPARAM lparam
)
3144 ime_trace( "himc %p\n", himc
);
3145 if (lparam
&& lparam
== (LPARAM
)himc
) return FALSE
;
3149 static void test_ImmEnumInputContext(void)
3153 ok_ret( 1, ImmEnumInputContext( 0, enum_get_context
, (LPARAM
)&default_himc
) );
3154 ok_ret( 1, ImmEnumInputContext( -1, enum_find_context
, 0 ) );
3155 ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context
, 0 ) );
3158 ok_ret( 0, ImmEnumInputContext( 1, enum_find_context
, 0 ) );
3160 ok_ret( 0, ImmEnumInputContext( GetCurrentProcessId(), enum_find_context
, 0 ) );
3162 himc
= ImmCreateContext();
3163 ok_ne( NULL
, himc
, HIMC
, "%p" );
3164 ok_ret( 0, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context
, (LPARAM
)himc
) );
3165 ok_ret( 1, ImmDestroyContext( himc
) );
3166 ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context
, (LPARAM
)himc
) );
3169 static void test_ImmInstallIME(void)
3174 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3175 SET_ENABLE( ImeInquire
, TRUE
);
3176 SET_ENABLE( ImeDestroy
, TRUE
);
3177 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3179 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3180 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3182 if (!(hkl
= ime_install())) goto cleanup
;
3184 SET_EXPECT( IME_DLL_PROCESS_ATTACH
);
3185 SET_EXPECT( ImeInquire
);
3186 ret
= ImmLoadIME( hkl
);
3187 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3188 CHECK_CALLED( IME_DLL_PROCESS_ATTACH
);
3189 CHECK_CALLED( ImeInquire
);
3191 ret
= ImmLoadIME( hkl
);
3192 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3194 SET_EXPECT( ImeDestroy
);
3195 SET_EXPECT( IME_DLL_PROCESS_DETACH
);
3196 ret
= ImmFreeLayout( hkl
);
3197 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3198 CHECK_CALLED( ImeDestroy
);
3199 CHECK_CALLED( IME_DLL_PROCESS_DETACH
);
3201 ret
= ImmFreeLayout( hkl
);
3202 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3204 ime_cleanup( hkl
, FALSE
);
3206 ime_info
.fdwProperty
= 0;
3208 if (!(hkl
= ime_install())) goto cleanup
;
3210 SET_EXPECT( IME_DLL_PROCESS_ATTACH
);
3211 SET_EXPECT( ImeInquire
);
3212 ret
= ImmLoadIME( hkl
);
3213 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3214 CHECK_CALLED( IME_DLL_PROCESS_ATTACH
);
3215 CHECK_CALLED( ImeInquire
);
3217 ret
= ImmLoadIME( hkl
);
3218 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3220 SET_EXPECT( ImeDestroy
);
3221 SET_EXPECT( IME_DLL_PROCESS_DETACH
);
3222 ret
= ImmFreeLayout( hkl
);
3223 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3224 CHECK_CALLED( ImeDestroy
);
3225 CHECK_CALLED( IME_DLL_PROCESS_DETACH
);
3227 ret
= ImmFreeLayout( hkl
);
3228 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3230 ime_cleanup( hkl
, FALSE
);
3233 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
3234 SET_ENABLE( ImeInquire
, FALSE
);
3235 SET_ENABLE( ImeDestroy
, FALSE
);
3236 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
3239 static void test_ImmIsIME(void)
3241 HKL hkl
= GetKeyboardLayout( 0 );
3243 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3244 SET_ENABLE( ImeInquire
, TRUE
);
3245 SET_ENABLE( ImeDestroy
, TRUE
);
3246 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3248 SetLastError( 0xdeadbeef );
3250 ok_ret( 0, ImmIsIME( 0 ) );
3251 ok_ret( 0xdeadbeef, GetLastError() );
3252 ok_ret( 1, ImmIsIME( hkl
) );
3254 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3255 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3257 if (!(hkl
= ime_install())) goto cleanup
;
3259 todo_ImeInquire
= TRUE
;
3260 todo_ImeDestroy
= TRUE
;
3261 todo_IME_DLL_PROCESS_ATTACH
= TRUE
;
3262 todo_IME_DLL_PROCESS_DETACH
= TRUE
;
3263 ok_ret( 1, ImmIsIME( hkl
) );
3264 todo_IME_DLL_PROCESS_ATTACH
= FALSE
;
3265 todo_IME_DLL_PROCESS_DETACH
= FALSE
;
3266 todo_ImeInquire
= FALSE
;
3267 todo_ImeDestroy
= FALSE
;
3269 ime_cleanup( hkl
, FALSE
);
3272 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
3273 SET_ENABLE( ImeInquire
, FALSE
);
3274 SET_ENABLE( ImeDestroy
, FALSE
);
3275 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
3278 static void test_ImmGetProperty(void)
3280 static const IMEINFO expect_ime_info
=
3282 .fdwProperty
= IME_PROP_UNICODE
| IME_PROP_AT_CARET
,
3284 static const IMEINFO expect_ime_info_0411
= /* MS Japanese IME */
3286 .fdwProperty
= IME_PROP_CANDLIST_START_FROM_1
| IME_PROP_UNICODE
| IME_PROP_AT_CARET
| 0xa,
3287 .fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
| IME_CMODE_KATAKANA
,
3288 .fdwSentenceCaps
= IME_SMODE_PLAURALCLAUSE
| IME_SMODE_CONVERSATION
,
3289 .fdwSCSCaps
= SCS_CAP_COMPSTR
| SCS_CAP_SETRECONVERTSTRING
| SCS_CAP_MAKEREAD
,
3290 .fdwSelectCaps
= SELECT_CAP_CONVERSION
| SELECT_CAP_SENTENCE
,
3291 .fdwUICaps
= UI_CAP_ROT90
,
3293 static const IMEINFO expect_ime_info_0412
= /* MS Korean IME */
3295 .fdwProperty
= IME_PROP_CANDLIST_START_FROM_1
| IME_PROP_UNICODE
| IME_PROP_AT_CARET
| 0xa,
3296 .fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
,
3297 .fdwSentenceCaps
= IME_SMODE_NONE
,
3298 .fdwSCSCaps
= SCS_CAP_COMPSTR
| SCS_CAP_SETRECONVERTSTRING
,
3299 .fdwSelectCaps
= SELECT_CAP_CONVERSION
,
3300 .fdwUICaps
= UI_CAP_ROT90
,
3302 static const IMEINFO expect_ime_info_0804
= /* MS Chinese IME */
3304 .fdwProperty
= IME_PROP_CANDLIST_START_FROM_1
| IME_PROP_UNICODE
| IME_PROP_AT_CARET
| 0xa,
3305 .fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
,
3306 .fdwSentenceCaps
= IME_SMODE_PLAURALCLAUSE
,
3307 .fdwSCSCaps
= SCS_CAP_COMPSTR
| SCS_CAP_SETRECONVERTSTRING
| SCS_CAP_MAKEREAD
,
3308 .fdwUICaps
= UI_CAP_ROT90
,
3310 HKL hkl
= GetKeyboardLayout( 0 );
3311 const IMEINFO
*expect
;
3313 SET_ENABLE( ImeInquire
, TRUE
);
3314 SET_ENABLE( ImeDestroy
, TRUE
);
3316 SetLastError( 0xdeadbeef );
3317 ok_ret( 0, ImmGetProperty( 0, 0 ) );
3318 ok_ret( 0, ImmGetProperty( hkl
, 0 ) );
3320 if (hkl
== (HKL
)0x04110411) expect
= &expect_ime_info_0411
;
3321 else if (hkl
== (HKL
)0x04120412) expect
= &expect_ime_info_0412
;
3322 else if (hkl
== (HKL
)0x08040804) expect
= &expect_ime_info_0804
;
3323 else expect
= &expect_ime_info
;
3325 /* IME_PROP_COMPLETE_ON_UNSELECT seems to be somtimes set on CJK locales IMEs, sometimes not */
3326 ok_ret( expect
->fdwProperty
, ImmGetProperty( hkl
, IGP_PROPERTY
) & ~IME_PROP_COMPLETE_ON_UNSELECT
);
3328 ok_ret( expect
->fdwConversionCaps
, ImmGetProperty( hkl
, IGP_CONVERSION
) );
3330 ok_ret( expect
->fdwSentenceCaps
, ImmGetProperty( hkl
, IGP_SENTENCE
) );
3331 ok_ret( expect
->fdwSCSCaps
, ImmGetProperty( hkl
, IGP_SETCOMPSTR
) );
3333 ok_ret( expect
->fdwSelectCaps
, ImmGetProperty( hkl
, IGP_SELECT
) );
3334 ok_ret( IMEVER_0400
, ImmGetProperty( hkl
, IGP_GETIMEVERSION
) );
3335 ok_ret( expect
->fdwUICaps
, ImmGetProperty( hkl
, IGP_UI
) );
3336 ok_ret( 0xdeadbeef, GetLastError() );
3338 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3339 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3341 if (!(hkl
= ime_install())) goto cleanup
;
3343 SET_EXPECT( ImeInquire
);
3344 SET_EXPECT( ImeDestroy
);
3345 ok_ret( 0, ImmGetProperty( hkl
, 0 ) );
3346 CHECK_CALLED( ImeInquire
);
3347 CHECK_CALLED( ImeDestroy
);
3350 todo_ImeInquire
= TRUE
;
3351 todo_ImeDestroy
= TRUE
;
3352 ok_ret( expect
->fdwProperty
, ImmGetProperty( hkl
, IGP_PROPERTY
) );
3353 ok_ret( expect
->fdwConversionCaps
, ImmGetProperty( hkl
, IGP_CONVERSION
) );
3354 ok_ret( expect
->fdwSentenceCaps
, ImmGetProperty( hkl
, IGP_SENTENCE
) );
3355 ok_ret( expect
->fdwSCSCaps
, ImmGetProperty( hkl
, IGP_SETCOMPSTR
) );
3356 ok_ret( expect
->fdwSelectCaps
, ImmGetProperty( hkl
, IGP_SELECT
) );
3357 ok_ret( IMEVER_0400
, ImmGetProperty( hkl
, IGP_GETIMEVERSION
) );
3358 ok_ret( expect
->fdwUICaps
, ImmGetProperty( hkl
, IGP_UI
) );
3359 todo_ImeInquire
= FALSE
;
3360 called_ImeInquire
= FALSE
;
3361 todo_ImeDestroy
= FALSE
;
3362 called_ImeDestroy
= FALSE
;
3364 ime_cleanup( hkl
, FALSE
);
3367 SET_ENABLE( ImeInquire
, FALSE
);
3368 SET_ENABLE( ImeDestroy
, FALSE
);
3371 static void test_ImmGetDescription(void)
3373 HKL hkl
= GetKeyboardLayout( 0 );
3374 WCHAR bufferW
[MAX_PATH
];
3375 char bufferA
[MAX_PATH
];
3378 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3379 SET_ENABLE( ImeInquire
, TRUE
);
3380 SET_ENABLE( ImeDestroy
, TRUE
);
3381 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3383 SetLastError( 0xdeadbeef );
3384 ret
= ImmGetDescriptionW( NULL
, NULL
, 0 );
3385 ok( !ret
, "ImmGetDescriptionW returned %lu\n", ret
);
3386 ret
= ImmGetDescriptionA( NULL
, NULL
, 0 );
3387 ok( !ret
, "ImmGetDescriptionA returned %lu\n", ret
);
3388 ret
= ImmGetDescriptionW( NULL
, NULL
, 100 );
3389 ok( !ret
, "ImmGetDescriptionW returned %lu\n", ret
);
3390 ret
= ImmGetDescriptionA( NULL
, NULL
, 100 );
3391 ok( !ret
, "ImmGetDescriptionA returned %lu\n", ret
);
3392 ret
= ImmGetDescriptionW( hkl
, bufferW
, 100 );
3393 ok( !ret
, "ImmGetDescriptionW returned %lu\n", ret
);
3394 ret
= ImmGetDescriptionA( hkl
, bufferA
, 100 );
3395 ok( !ret
, "ImmGetDescriptionA returned %lu\n", ret
);
3396 ret
= GetLastError();
3397 ok( ret
== 0xdeadbeef, "got error %lu\n", ret
);
3399 if (!(hkl
= ime_install())) goto cleanup
;
3401 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3402 ret
= ImmGetDescriptionW( hkl
, bufferW
, 2 );
3403 ok( ret
== 1, "ImmGetDescriptionW returned %lu\n", ret
);
3404 ok( !wcscmp( bufferW
, L
"W" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3405 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3406 ret
= ImmGetDescriptionA( hkl
, bufferA
, 2 );
3407 ok( ret
== 0, "ImmGetDescriptionA returned %lu\n", ret
);
3408 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3410 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3411 ret
= ImmGetDescriptionW( hkl
, bufferW
, 11 );
3412 ok( ret
== 10, "ImmGetDescriptionW returned %lu\n", ret
);
3413 ok( !wcscmp( bufferW
, L
"WineTest I" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3414 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3415 ret
= ImmGetDescriptionA( hkl
, bufferA
, 11 );
3416 ok( ret
== 0, "ImmGetDescriptionA returned %lu\n", ret
);
3417 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3419 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3420 ret
= ImmGetDescriptionW( hkl
, bufferW
, 12 );
3421 ok( ret
== 11, "ImmGetDescriptionW returned %lu\n", ret
);
3422 ok( !wcscmp( bufferW
, L
"WineTest IM" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3423 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3424 ret
= ImmGetDescriptionA( hkl
, bufferA
, 12 );
3425 ok( ret
== 12, "ImmGetDescriptionA returned %lu\n", ret
);
3426 ok( !strcmp( bufferA
, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3428 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3429 ret
= ImmGetDescriptionW( hkl
, bufferW
, 13 );
3430 ok( ret
== 12, "ImmGetDescriptionW returned %lu\n", ret
);
3431 ok( !wcscmp( bufferW
, L
"WineTest IME" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3432 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3433 ret
= ImmGetDescriptionA( hkl
, bufferA
, 13 );
3434 ok( ret
== 12, "ImmGetDescriptionA returned %lu\n", ret
);
3435 ok( !strcmp( bufferA
, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3437 ime_cleanup( hkl
, FALSE
);
3440 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
3441 SET_ENABLE( ImeInquire
, FALSE
);
3442 SET_ENABLE( ImeDestroy
, FALSE
);
3443 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
3446 static void test_ImmGetIMEFileName(void)
3448 HKL hkl
= GetKeyboardLayout( 0 );
3449 WCHAR bufferW
[MAX_PATH
], expectW
[16];
3450 char bufferA
[MAX_PATH
], expectA
[16];
3453 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3454 SET_ENABLE( ImeInquire
, TRUE
);
3455 SET_ENABLE( ImeDestroy
, TRUE
);
3456 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3458 SetLastError( 0xdeadbeef );
3459 ret
= ImmGetIMEFileNameW( NULL
, NULL
, 0 );
3460 ok( !ret
, "ImmGetIMEFileNameW returned %lu\n", ret
);
3461 ret
= ImmGetIMEFileNameA( NULL
, NULL
, 0 );
3462 ok( !ret
, "ImmGetIMEFileNameA returned %lu\n", ret
);
3463 ret
= ImmGetIMEFileNameW( NULL
, NULL
, 100 );
3464 ok( !ret
, "ImmGetIMEFileNameW returned %lu\n", ret
);
3465 ret
= ImmGetIMEFileNameA( NULL
, NULL
, 100 );
3466 ok( !ret
, "ImmGetIMEFileNameA returned %lu\n", ret
);
3467 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 100 );
3468 ok( !ret
, "ImmGetIMEFileNameW returned %lu\n", ret
);
3469 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 100 );
3470 ok( !ret
, "ImmGetIMEFileNameA returned %lu\n", ret
);
3471 ret
= GetLastError();
3472 ok( ret
== 0xdeadbeef, "got error %lu\n", ret
);
3474 if (!(hkl
= ime_install())) goto cleanup
;
3476 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3477 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 2 );
3478 ok( ret
== 1, "ImmGetIMEFileNameW returned %lu\n", ret
);
3479 ok( !wcscmp( bufferW
, L
"W" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3480 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3481 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 2 );
3482 ok( ret
== 0, "ImmGetIMEFileNameA returned %lu\n", ret
);
3483 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3485 swprintf( expectW
, ARRAY_SIZE(expectW
), L
"WINE%04X.I", ime_count
- 1 );
3486 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3487 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 11 );
3488 ok( ret
== 10, "ImmGetIMEFileNameW returned %lu\n", ret
);
3489 ok( !wcscmp( bufferW
, expectW
), "got bufferW %s\n", debugstr_w(bufferW
) );
3490 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3491 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 11 );
3492 ok( ret
== 0, "ImmGetIMEFileNameA returned %lu\n", ret
);
3493 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3495 swprintf( expectW
, ARRAY_SIZE(expectW
), L
"WINE%04X.IM", ime_count
- 1 );
3496 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3497 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 12 );
3498 ok( ret
== 11, "ImmGetIMEFileNameW returned %lu\n", ret
);
3499 ok( !wcscmp( bufferW
, expectW
), "got bufferW %s\n", debugstr_w(bufferW
) );
3500 snprintf( expectA
, ARRAY_SIZE(expectA
), "WINE%04X.IME", ime_count
- 1 );
3501 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3502 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 12 );
3503 ok( ret
== 12, "ImmGetIMEFileNameA returned %lu\n", ret
);
3504 ok( !strcmp( bufferA
, expectA
), "got bufferA %s\n", debugstr_a(bufferA
) );
3506 swprintf( expectW
, ARRAY_SIZE(expectW
), L
"WINE%04X.IME", ime_count
- 1 );
3507 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3508 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 13 );
3509 ok( ret
== 12, "ImmGetIMEFileNameW returned %lu\n", ret
);
3510 ok( !wcscmp( bufferW
, expectW
), "got bufferW %s\n", debugstr_w(bufferW
) );
3511 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3512 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 13 );
3513 ok( ret
== 12, "ImmGetIMEFileNameA returned %lu\n", ret
);
3514 ok( !strcmp( bufferA
, expectA
), "got bufferA %s\n", debugstr_a(bufferA
) );
3516 ime_cleanup( hkl
, FALSE
);
3519 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
3520 SET_ENABLE( ImeInquire
, FALSE
);
3521 SET_ENABLE( ImeDestroy
, FALSE
);
3522 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
3525 static void test_ImmEscape( BOOL unicode
)
3527 HKL hkl
= GetKeyboardLayout( 0 );
3530 IME_ESC_QUERY_SUPPORT
,
3531 IME_ESC_SEQUENCE_TO_INTERNAL
,
3532 IME_ESC_GET_EUDC_DICTIONARY
,
3533 IME_ESC_SET_EUDC_DICTIONARY
,
3537 IME_ESC_GETHELPFILENAME
,
3542 SET_ENABLE( ImeEscape
, TRUE
);
3544 winetest_push_context( unicode
? "unicode" : "ansi" );
3546 ok_ret( 0, ImmEscapeW( hkl
, 0, 0, NULL
) );
3547 ok_ret( 0, ImmEscapeA( hkl
, 0, 0, NULL
) );
3549 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3550 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3551 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
3553 if (!(hkl
= ime_install())) goto cleanup
;
3555 for (i
= 0; i
< ARRAY_SIZE(codes
); ++i
)
3557 winetest_push_context( "esc %#lx", codes
[i
] );
3559 SET_EXPECT( ImeEscape
);
3560 ok_ret( 4, ImmEscapeW( hkl
, 0, codes
[i
], NULL
) );
3561 CHECK_CALLED( ImeEscape
);
3563 SET_EXPECT( ImeEscape
);
3564 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3565 if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
) wcscpy( bufferW
, L
"EscapeIme" );
3566 ok_ret( 4, ImmEscapeW( hkl
, 0, codes
[i
], bufferW
) );
3567 if (unicode
|| codes
[i
] == IME_ESC_GET_EUDC_DICTIONARY
|| codes
[i
] == IME_ESC_IME_NAME
||
3568 codes
[i
] == IME_ESC_GETHELPFILENAME
)
3570 ok_wcs( L
"ImeEscape", bufferW
);
3571 ok_eq( 0xcdcd, bufferW
[10], WORD
, "%#x" );
3573 else if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
)
3575 ok_wcs( L
"EscapeIme", bufferW
);
3576 ok_eq( 0xcdcd, bufferW
[10], WORD
, "%#x" );
3578 else if (codes
[i
] == IME_ESC_HANJA_MODE
)
3581 ok_eq( 0xcdcd, bufferW
[0], WORD
, "%#x" );
3585 ok( !memcmp( bufferW
, "ImeEscape", 10 ), "got bufferW %s\n", debugstr_w(bufferW
) );
3586 ok_eq( 0xcdcd, bufferW
[5], WORD
, "%#x" );
3588 CHECK_CALLED( ImeEscape
);
3590 SET_EXPECT( ImeEscape
);
3591 ok_ret( 4, ImmEscapeA( hkl
, 0, codes
[i
], NULL
) );
3592 CHECK_CALLED( ImeEscape
);
3594 SET_EXPECT( ImeEscape
);
3595 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3596 if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
) strcpy( bufferA
, "EscapeIme" );
3597 ok_ret( 4, ImmEscapeA( hkl
, 0, codes
[i
], bufferA
) );
3598 if (!unicode
|| codes
[i
] == IME_ESC_GET_EUDC_DICTIONARY
|| codes
[i
] == IME_ESC_IME_NAME
||
3599 codes
[i
] == IME_ESC_GETHELPFILENAME
)
3601 ok_str( "ImeEscape", bufferA
);
3602 ok_eq( 0xcd, bufferA
[10], BYTE
, "%#x" );
3604 else if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
)
3606 ok_str( "EscapeIme", bufferA
);
3607 ok_eq( 0xcd, bufferA
[10], BYTE
, "%#x" );
3609 else if (codes
[i
] == IME_ESC_HANJA_MODE
)
3612 ok_eq( 0xcd, bufferA
[0], BYTE
, "%#x" );
3616 ok( !memcmp( bufferA
, L
"ImeEscape", 10 * sizeof(WCHAR
) ), "got bufferA %s\n", debugstr_a(bufferA
) );
3617 ok_eq( 0xcd, bufferA
[20], BYTE
, "%#x" );
3619 CHECK_CALLED( ImeEscape
);
3621 winetest_pop_context();
3624 ime_cleanup( hkl
, FALSE
);
3627 SET_ENABLE( ImeEscape
, FALSE
);
3629 winetest_pop_context();
3632 static int CALLBACK
enum_register_wordA( const char *reading
, DWORD style
, const char *string
, void *user
)
3634 ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_a(reading
), style
, debugstr_a(string
), user
);
3636 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
3637 ok_str( "Reading", reading
);
3638 ok_str( "String", string
);
3643 static int CALLBACK
enum_register_wordW( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
, void *user
)
3645 ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_w(reading
), style
, debugstr_w(string
), user
);
3647 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
3648 ok_wcs( L
"Reading", reading
);
3649 ok_wcs( L
"String", string
);
3654 static void test_ImmEnumRegisterWord( BOOL unicode
)
3656 HKL hkl
= GetKeyboardLayout( 0 );
3658 winetest_push_context( unicode
? "unicode" : "ansi" );
3660 SET_ENABLE( ImeEnumRegisterWord
, TRUE
);
3662 SetLastError( 0xdeadbeef );
3663 ok_ret( 0, ImmEnumRegisterWordW( NULL
, enum_register_wordW
, NULL
, 0, NULL
, NULL
) );
3664 ok_ret( 0, ImmEnumRegisterWordA( NULL
, enum_register_wordA
, NULL
, 0, NULL
, NULL
) );
3665 ok_ret( 0, ImmEnumRegisterWordW( hkl
, enum_register_wordW
, NULL
, 0, NULL
, NULL
) );
3666 ok_ret( 0, ImmEnumRegisterWordA( hkl
, enum_register_wordA
, NULL
, 0, NULL
, NULL
) );
3668 ok_ret( 0xdeadbeef, GetLastError() );
3670 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3671 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3672 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
3674 if (!(hkl
= ime_install())) goto cleanup
;
3676 SET_EXPECT( ImeEnumRegisterWord
);
3677 ok_ret( 0, ImmEnumRegisterWordW( hkl
, enum_register_wordW
, NULL
, 0, NULL
, NULL
) );
3678 CHECK_CALLED( ImeEnumRegisterWord
);
3680 SET_EXPECT( ImeEnumRegisterWord
);
3681 ok_ret( 0, ImmEnumRegisterWordA( hkl
, enum_register_wordA
, NULL
, 0, NULL
, NULL
) );
3682 CHECK_CALLED( ImeEnumRegisterWord
);
3684 SET_EXPECT( ImeEnumRegisterWord
);
3685 ok_ret( 0xdeadbeef, ImmEnumRegisterWordW( hkl
, enum_register_wordW
, L
"Reading", 0xdeadbeef, L
"String", NULL
) );
3686 CHECK_CALLED( ImeEnumRegisterWord
);
3688 SET_EXPECT( ImeEnumRegisterWord
);
3689 ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl
, enum_register_wordA
, "Reading", 0xdeadbeef, "String", NULL
) );
3690 CHECK_CALLED( ImeEnumRegisterWord
);
3692 ime_cleanup( hkl
, FALSE
);
3695 SET_ENABLE( ImeEnumRegisterWord
, FALSE
);
3697 winetest_pop_context();
3700 static void test_ImmRegisterWord( BOOL unicode
)
3702 HKL hkl
= GetKeyboardLayout( 0 );
3704 SET_ENABLE( ImeRegisterWord
, TRUE
);
3706 winetest_push_context( unicode
? "unicode" : "ansi" );
3708 SetLastError( 0xdeadbeef );
3709 ok_ret( 0, ImmRegisterWordW( NULL
, NULL
, 0, NULL
) );
3710 ok_ret( 0, ImmRegisterWordA( NULL
, NULL
, 0, NULL
) );
3711 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0, NULL
) );
3712 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0, NULL
) );
3714 ok_ret( 0xdeadbeef, GetLastError() );
3716 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3717 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3718 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
3720 if (!(hkl
= ime_install())) goto cleanup
;
3722 SET_EXPECT( ImeRegisterWord
);
3723 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0, NULL
) );
3724 CHECK_CALLED( ImeRegisterWord
);
3726 SET_EXPECT( ImeRegisterWord
);
3727 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0, NULL
) );
3728 CHECK_CALLED( ImeRegisterWord
);
3730 SET_EXPECT( ImeRegisterWord
);
3731 ok_ret( 0, ImmRegisterWordW( hkl
, L
"Reading", 0, NULL
) );
3732 CHECK_CALLED( ImeRegisterWord
);
3734 SET_EXPECT( ImeRegisterWord
);
3735 ok_ret( 0, ImmRegisterWordA( hkl
, "Reading", 0, NULL
) );
3736 CHECK_CALLED( ImeRegisterWord
);
3738 SET_EXPECT( ImeRegisterWord
);
3739 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0xdeadbeef, NULL
) );
3740 CHECK_CALLED( ImeRegisterWord
);
3742 SET_EXPECT( ImeRegisterWord
);
3743 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0xdeadbeef, NULL
) );
3744 CHECK_CALLED( ImeRegisterWord
);
3746 SET_EXPECT( ImeRegisterWord
);
3747 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0, L
"String" ) );
3748 CHECK_CALLED( ImeRegisterWord
);
3750 SET_EXPECT( ImeRegisterWord
);
3751 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0, "String" ) );
3752 CHECK_CALLED( ImeRegisterWord
);
3754 ime_cleanup( hkl
, FALSE
);
3757 SET_ENABLE( ImeRegisterWord
, FALSE
);
3759 winetest_pop_context();
3762 static void test_ImmGetRegisterWordStyle( BOOL unicode
)
3764 HKL hkl
= GetKeyboardLayout( 0 );
3768 winetest_push_context( unicode
? "unicode" : "ansi" );
3770 SET_ENABLE( ImeGetRegisterWordStyle
, TRUE
);
3772 SetLastError( 0xdeadbeef );
3773 ok_ret( 0, ImmGetRegisterWordStyleW( NULL
, 0, &styleW
) );
3774 ok_ret( 0, ImmGetRegisterWordStyleA( NULL
, 0, &styleA
) );
3775 ok_ret( 0, ImmGetRegisterWordStyleW( hkl
, 0, &styleW
) );
3776 ok_ret( 0, ImmGetRegisterWordStyleA( hkl
, 0, &styleA
) );
3778 ok_ret( 0xdeadbeef, GetLastError() );
3780 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3781 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3782 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
3784 if (!(hkl
= ime_install())) goto cleanup
;
3786 if (!strcmp( winetest_platform
, "wine" )) goto skip_null
;
3788 SET_EXPECT( ImeGetRegisterWordStyle
);
3789 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl
, 16, NULL
) );
3790 CHECK_CALLED( ImeGetRegisterWordStyle
);
3792 SET_EXPECT( ImeGetRegisterWordStyle
);
3793 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl
, 16, NULL
) );
3794 CHECK_CALLED( ImeGetRegisterWordStyle
);
3797 SET_EXPECT( ImeGetRegisterWordStyle
);
3798 memset( &styleW
, 0xcd, sizeof(styleW
) );
3799 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl
, 1, &styleW
) );
3800 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3802 ok_eq( 0xdeadbeef, styleW
.dwStyle
, UINT
, "%#x" );
3803 ok_wcs( L
"StyleDescription", styleW
.szDescription
);
3808 ok_eq( 0xcdcdcdcd, styleW
.dwStyle
, UINT
, "%#x" );
3810 ok_eq( 0xcdcd, styleW
.szDescription
[0], WORD
, "%#x" );
3812 CHECK_CALLED( ImeGetRegisterWordStyle
);
3814 SET_EXPECT( ImeGetRegisterWordStyle
);
3815 memset( &styleA
, 0xcd, sizeof(styleA
) );
3816 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl
, 1, &styleA
) );
3817 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3820 ok_eq( 0xcdcdcdcd, styleA
.dwStyle
, UINT
, "%#x" );
3822 ok_eq( 0xcd, styleA
.szDescription
[0], BYTE
, "%#x" );
3826 ok_eq( 0xdeadbeef, styleA
.dwStyle
, UINT
, "%#x" );
3827 ok_str( "StyleDescription", styleA
.szDescription
);
3829 CHECK_CALLED( ImeGetRegisterWordStyle
);
3831 ime_cleanup( hkl
, FALSE
);
3834 SET_ENABLE( ImeGetRegisterWordStyle
, FALSE
);
3836 winetest_pop_context();
3839 static void test_ImmUnregisterWord( BOOL unicode
)
3841 HKL hkl
= GetKeyboardLayout( 0 );
3843 winetest_push_context( unicode
? "unicode" : "ansi" );
3845 SET_ENABLE( ImeUnregisterWord
, TRUE
);
3847 SetLastError( 0xdeadbeef );
3848 ok_ret( 0, ImmUnregisterWordW( NULL
, NULL
, 0, NULL
) );
3849 ok_ret( 0, ImmUnregisterWordA( NULL
, NULL
, 0, NULL
) );
3850 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0, NULL
) );
3851 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0, NULL
) );
3853 ok_ret( 0xdeadbeef, GetLastError() );
3855 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3856 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3857 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
3859 if (!(hkl
= ime_install())) goto cleanup
;
3861 SET_EXPECT( ImeUnregisterWord
);
3862 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0, NULL
) );
3863 CHECK_CALLED( ImeUnregisterWord
);
3865 SET_EXPECT( ImeUnregisterWord
);
3866 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0, NULL
) );
3867 CHECK_CALLED( ImeUnregisterWord
);
3869 SET_EXPECT( ImeUnregisterWord
);
3870 ok_ret( 0, ImmUnregisterWordW( hkl
, L
"Reading", 0, NULL
) );
3871 CHECK_CALLED( ImeUnregisterWord
);
3873 SET_EXPECT( ImeUnregisterWord
);
3874 ok_ret( 0, ImmUnregisterWordA( hkl
, "Reading", 0, NULL
) );
3875 CHECK_CALLED( ImeUnregisterWord
);
3877 SET_EXPECT( ImeUnregisterWord
);
3878 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0xdeadbeef, NULL
) );
3879 CHECK_CALLED( ImeUnregisterWord
);
3881 SET_EXPECT( ImeUnregisterWord
);
3882 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0xdeadbeef, NULL
) );
3883 CHECK_CALLED( ImeUnregisterWord
);
3885 SET_EXPECT( ImeUnregisterWord
);
3886 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0, L
"String" ) );
3887 CHECK_CALLED( ImeUnregisterWord
);
3889 SET_EXPECT( ImeUnregisterWord
);
3890 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0, "String" ) );
3891 CHECK_CALLED( ImeUnregisterWord
);
3893 ime_cleanup( hkl
, FALSE
);
3896 SET_ENABLE( ImeUnregisterWord
, FALSE
);
3898 winetest_pop_context();
3901 static void test_ImmProcessKey(void)
3903 const struct ime_call process_key_seq
[] =
3906 .hkl
= expect_ime
, .himc
= default_himc
,
3907 .func
= IME_PROCESS_KEY
, .process_key
= {.vkey
= 'A', .key_data
= 0},
3911 HKL hkl
, old_hkl
= GetKeyboardLayout( 0 );
3914 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
3915 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
3916 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
3919 ok_ret( 0, ImmProcessKey( hwnd
, old_hkl
, 'A', 0, 0 ) );
3920 ok_seq( empty_sequence
);
3922 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
3924 if (!(hkl
= ime_install())) goto cleanup
;
3926 ok_ret( 1, ImmActivateLayout( hkl
) );
3927 ok_ret( 1, ImmLoadIME( hkl
) );
3929 memset( ime_calls
, 0, sizeof(ime_calls
) );
3932 ok_ret( 0, ImmProcessKey( 0, hkl
, 'A', 0, 0 ) );
3933 ok_seq( empty_sequence
);
3935 ret
= ImmProcessKey( hwnd
, hkl
, 'A', 0, 0 );
3938 ok_seq( process_key_seq
);
3940 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3941 ok_ret( 0, ImmProcessKey( hwnd
, old_hkl
, 'A', 0, 0 ) );
3943 ok_seq( empty_sequence
);
3944 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3946 ok_ret( 1, ImmActivateLayout( old_hkl
) );
3948 ime_cleanup( hkl
, TRUE
);
3950 memset( ime_calls
, 0, sizeof(ime_calls
) );
3954 ok_ret( 1, DestroyWindow( hwnd
) );
3963 static BOOL CALLBACK
enum_thread_ime_windows( HWND hwnd
, LPARAM lparam
)
3965 struct ime_windows
*params
= (void *)lparam
;
3969 ime_trace( "hwnd %p, lparam %#Ix\n", hwnd
, lparam
);
3971 ret
= RealGetWindowClassW( hwnd
, buffer
, ARRAY_SIZE(buffer
) );
3972 ok( ret
, "RealGetWindowClassW returned %#x\n", ret
);
3974 if (!wcscmp( buffer
, L
"IME" ))
3976 ok( !params
->ime_hwnd
, "Found extra IME window %p\n", hwnd
);
3977 params
->ime_hwnd
= hwnd
;
3979 if (!wcscmp( buffer
, ime_ui_class
.lpszClassName
))
3981 ok( !params
->ime_ui_hwnd
, "Found extra IME UI window %p\n", hwnd
);
3982 params
->ime_ui_hwnd
= hwnd
;
3988 static void test_ImmActivateLayout(void)
3990 const struct ime_call activate_seq
[] =
3993 .hkl
= expect_ime
, .himc
= default_himc
,
3994 .func
= IME_SELECT
, .select
= 1,
3998 const struct ime_call deactivate_seq
[] =
4001 .hkl
= expect_ime
, .himc
= default_himc
,
4002 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4006 .hkl
= default_hkl
, .himc
= default_himc
,
4007 .func
= IME_SELECT
, .select
= 0,
4011 struct ime_call activate_with_window_seq
[] =
4014 .hkl
= expect_ime
, .himc
= default_himc
,
4015 .func
= IME_SELECT
, .select
= 1,
4019 .hkl
= expect_ime
, .himc
= 0/*himc*/,
4020 .func
= IME_SELECT
, .select
= 1,
4024 .hkl
= expect_ime
, .himc
= default_himc
,
4025 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 1, .lparam
= (LPARAM
)expect_ime
},
4028 .hkl
= expect_ime
, .himc
= default_himc
,
4029 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_OPENSTATUSWINDOW
},
4033 .hkl
= expect_ime
, .himc
= default_himc
,
4034 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
4035 .todo
= TRUE
, .broken
= (default_hkl
== (HKL
)0x04120412),
4038 .hkl
= expect_ime
, .himc
= default_himc
,
4039 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
4044 struct ime_call deactivate_with_window_seq
[] =
4047 .hkl
= expect_ime
, .himc
= default_himc
,
4048 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4049 .todo
= TRUE
, .flaky_himc
= TRUE
,
4052 .hkl
= expect_ime
, .himc
= 0/*himc*/,
4053 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4054 .todo
= TRUE
, .flaky_himc
= TRUE
,
4057 .hkl
= expect_ime
, .himc
= default_himc
,
4058 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_CLOSESTATUSWINDOW
},
4062 .hkl
= expect_ime
, .himc
= default_himc
,
4063 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 0, .lparam
= (LPARAM
)expect_ime
},
4066 .hkl
= default_hkl
, .himc
= default_himc
,
4067 .func
= IME_SELECT
, .select
= 0,
4071 .hkl
= default_hkl
, .himc
= 0/*himc*/,
4072 .func
= IME_SELECT
, .select
= 0,
4077 HKL hkl
, old_hkl
= GetKeyboardLayout( 0 );
4078 struct ime_windows ime_windows
= {0};
4082 SET_ENABLE( ImeInquire
, TRUE
);
4083 SET_ENABLE( ImeDestroy
, TRUE
);
4085 ok_ret( 1, ImmActivateLayout( old_hkl
) );
4087 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
4089 if (!(hkl
= ime_install())) goto cleanup
;
4091 /* ActivateKeyboardLayout doesn't call ImeInquire / ImeDestroy */
4093 ok_seq( empty_sequence
);
4094 ok_eq( old_hkl
, ActivateKeyboardLayout( hkl
, 0 ), HKL
, "%p" );
4095 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4096 ok_eq( hkl
, ActivateKeyboardLayout( old_hkl
, 0 ), HKL
, "%p" );
4097 ok_seq( empty_sequence
);
4098 ok_eq( old_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4101 /* ImmActivateLayout changes active HKL */
4103 SET_EXPECT( ImeInquire
);
4104 ok_ret( 1, ImmActivateLayout( hkl
) );
4105 ok_seq( activate_seq
);
4106 CHECK_CALLED( ImeInquire
);
4107 ok_ret( 1, ImmLoadIME( hkl
) );
4109 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4111 ok_ret( 1, ImmActivateLayout( hkl
) );
4112 ok_seq( empty_sequence
);
4114 todo_ImeDestroy
= TRUE
; /* Wine doesn't leak the IME */
4115 ok_ret( 1, ImmActivateLayout( old_hkl
) );
4116 ok_seq( deactivate_seq
);
4117 todo_ImeDestroy
= FALSE
;
4119 ok_eq( old_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4121 ime_cleanup( hkl
, FALSE
);
4122 ok_seq( empty_sequence
);
4125 /* ImmActivateLayout leaks the IME, we need to free it manually */
4127 SET_EXPECT( ImeDestroy
);
4128 ret
= ImmFreeLayout( hkl
);
4129 ok( ret
, "ImmFreeLayout returned %u\n", ret
);
4130 CHECK_CALLED( ImeDestroy
);
4131 ok_seq( empty_sequence
);
4134 /* when there's a window, ActivateKeyboardLayout calls ImeInquire */
4136 if (!(hkl
= ime_install())) goto cleanup
;
4138 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
4139 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
4140 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
4142 ok_seq( empty_sequence
);
4144 himc
= ImmCreateContext();
4145 ok( !!himc
, "got himc %p\n", himc
);
4146 ok_seq( empty_sequence
);
4148 SET_EXPECT( ImeInquire
);
4149 ok_eq( old_hkl
, ActivateKeyboardLayout( hkl
, 0 ), HKL
, "%p" );
4150 CHECK_CALLED( ImeInquire
);
4151 activate_with_window_seq
[1].himc
= himc
;
4152 ok_seq( activate_with_window_seq
);
4153 todo_ImeInquire
= TRUE
;
4154 ok_ret( 1, ImmLoadIME( hkl
) );
4155 todo_ImeInquire
= FALSE
;
4157 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4159 /* FIXME: ignore spurious VK_CONTROL ImeProcessKey / ImeToAsciiEx calls */
4161 memset( ime_calls
, 0, sizeof(ime_calls
) );
4164 todo_ImeDestroy
= TRUE
; /* Wine doesn't leak the IME */
4165 ok_eq( hkl
, ActivateKeyboardLayout( old_hkl
, 0 ), HKL
, "%p" );
4166 todo_ImeDestroy
= FALSE
;
4167 deactivate_with_window_seq
[1].himc
= himc
;
4168 deactivate_with_window_seq
[5].himc
= himc
;
4169 ok_seq( deactivate_with_window_seq
);
4171 ok_eq( old_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4173 ok_ret( 1, ImmDestroyContext( himc
) );
4174 ok_seq( empty_sequence
);
4177 todo_ImeInquire
= TRUE
;
4178 ok_eq( old_hkl
, ActivateKeyboardLayout( hkl
, 0 ), HKL
, "%p" );
4179 todo_ImeInquire
= FALSE
;
4180 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4182 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows
, (LPARAM
)&ime_windows
) );
4183 ok( !!ime_windows
.ime_hwnd
, "missing IME window\n" );
4184 ok( !!ime_windows
.ime_ui_hwnd
, "missing IME UI window\n" );
4185 ok_ret( (UINT_PTR
)ime_windows
.ime_hwnd
, (UINT_PTR
)GetParent( ime_windows
.ime_ui_hwnd
) );
4187 todo_ImeDestroy
= TRUE
; /* Wine doesn't leak the IME */
4188 ok_eq( hkl
, ActivateKeyboardLayout( old_hkl
, 0 ), HKL
, "%p" );
4189 todo_ImeDestroy
= FALSE
;
4190 ok_eq( old_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4193 SET_EXPECT( ImeDestroy
);
4194 ime_cleanup( hkl
, TRUE
);
4195 CHECK_CALLED( ImeDestroy
);
4197 ok_ret( 1, DestroyWindow( hwnd
) );
4199 memset( ime_calls
, 0, sizeof(ime_calls
) );
4204 SET_ENABLE( ImeInquire
, FALSE
);
4205 SET_ENABLE( ImeDestroy
, FALSE
);
4208 static void test_ImmCreateInputContext(void)
4210 struct ime_call activate_seq
[] =
4213 .hkl
= expect_ime
, .himc
= default_himc
,
4214 .func
= IME_SELECT
, .select
= 1,
4218 .hkl
= expect_ime
, .himc
= 0/*himc[0]*/,
4219 .func
= IME_SELECT
, .select
= 1,
4223 .hkl
= expect_ime
, .himc
= default_himc
,
4224 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 1, .lparam
= (LPARAM
)expect_ime
},
4227 .hkl
= expect_ime
, .himc
= default_himc
,
4228 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_OPENSTATUSWINDOW
},
4233 struct ime_call select1_seq
[] =
4236 .hkl
= expect_ime
, .himc
= 0/*himc[1]*/,
4237 .func
= IME_SELECT
, .select
= 1,
4242 struct ime_call select0_seq
[] =
4245 .hkl
= expect_ime
, .himc
= 0/*himc[1]*/,
4246 .func
= IME_SELECT
, .select
= 0,
4250 struct ime_call deactivate_seq
[] =
4253 .hkl
= expect_ime
, .himc
= default_himc
,
4254 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4255 .todo
= TRUE
, .flaky_himc
= TRUE
,
4258 .hkl
= expect_ime
, .himc
= 0/*himc[0]*/,
4259 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4260 .todo
= TRUE
, .flaky_himc
= TRUE
,
4263 .hkl
= expect_ime
, .himc
= default_himc
,
4264 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_CLOSESTATUSWINDOW
},
4268 .hkl
= expect_ime
, .himc
= default_himc
,
4269 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 0, .lparam
= (LPARAM
)expect_ime
},
4272 .hkl
= default_hkl
, .himc
= default_himc
,
4273 .func
= IME_SELECT
, .select
= 0,
4277 .hkl
= default_hkl
, .himc
= 0/*himc[0]*/,
4278 .func
= IME_SELECT
, .select
= 0,
4283 HKL hkl
, old_hkl
= GetKeyboardLayout( 0 );
4288 ctx
= ImmLockIMC( default_himc
);
4289 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4290 ok_ret( 0, IsWindow( ctx
->hWnd
) );
4291 ok_ret( 1, ImmUnlockIMC( default_himc
) );
4294 /* new input contexts cannot be locked before IME window has been created */
4296 himc
[0] = ImmCreateContext();
4297 ok( !!himc
[0], "ImmCreateContext failed, error %lu\n", GetLastError() );
4298 ctx
= ImmLockIMC( himc
[0] );
4300 ok( !ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4301 if (ctx
) ImmUnlockIMCC( himc
[0] );
4303 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
4304 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
4305 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
4308 ctx
= ImmLockIMC( default_himc
);
4309 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4310 ok_ret( 1, ImmUnlockIMC( default_himc
) );
4312 ctx
= ImmLockIMC( himc
[0] );
4313 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4314 ok_ret( 1, ImmUnlockIMC( himc
[0] ) );
4317 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
4318 ime_info
.dwPrivateDataSize
= 123;
4320 if (!(hkl
= ime_install())) goto cleanup
;
4322 ok_ret( 1, ImmLoadIME( hkl
) );
4324 /* Activating the layout calls ImeSelect 1 on existing HIMC */
4326 ok_seq( empty_sequence
);
4327 ok_ret( 1, ImmActivateLayout( hkl
) );
4328 activate_seq
[1].himc
= himc
[0];
4329 ok_seq( activate_seq
);
4331 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4333 ctx
= ImmLockIMC( default_himc
);
4334 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4335 ok_ret( 1, ImmUnlockIMC( default_himc
) );
4337 ctx
= ImmLockIMC( himc
[0] );
4338 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4339 ok_ret( 1, ImmUnlockIMC( himc
[0] ) );
4342 /* ImmLockIMC triggers the ImeSelect call, to allocate private data */
4344 himc
[1] = ImmCreateContext();
4345 ok( !!himc
[1], "ImmCreateContext failed, error %lu\n", GetLastError() );
4348 ok_seq( empty_sequence
);
4349 ctx
= ImmLockIMC( himc
[1] );
4350 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
4351 select1_seq
[0].himc
= himc
[1];
4352 ok_seq( select1_seq
);
4354 ok_ret( 1, ImmUnlockIMC( himc
[1] ) );
4356 ok_seq( empty_sequence
);
4357 ok_ret( 1, ImmDestroyContext( himc
[1] ) );
4358 select0_seq
[0].himc
= himc
[1];
4359 ok_seq( select0_seq
);
4362 /* Deactivating the layout calls ImeSelect 0 on existing HIMC */
4364 ok_ret( 1, ImmActivateLayout( old_hkl
) );
4365 deactivate_seq
[1].himc
= himc
[0];
4366 deactivate_seq
[5].himc
= himc
[0];
4367 ok_seq( deactivate_seq
);
4369 ok_eq( old_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4371 ime_cleanup( hkl
, TRUE
);
4372 ok_seq( empty_sequence
);
4375 ok_ret( 1, ImmDestroyContext( himc
[0] ) );
4376 ok_ret( 1, DestroyWindow( hwnd
) );
4378 memset( ime_calls
, 0, sizeof(ime_calls
) );
4381 ime_info
.dwPrivateDataSize
= 0;
4384 static void test_DefWindowProc(void)
4386 const struct ime_call start_composition_seq
[] =
4388 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_STARTCOMPOSITION
}},
4391 const struct ime_call end_composition_seq
[] =
4393 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
}},
4396 const struct ime_call composition_seq
[] =
4398 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_COMPOSITION
}},
4401 const struct ime_call set_context_seq
[] =
4403 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
}},
4406 const struct ime_call notify_seq
[] =
4408 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
}},
4411 HKL hkl
, old_hkl
= GetKeyboardLayout( 0 );
4414 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
4416 if (!(hkl
= ime_install())) return;
4418 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
4419 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
4420 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
4422 ok_ret( 1, ImmActivateLayout( hkl
) );
4423 ok_ret( 1, ImmLoadIME( hkl
) );
4425 memset( ime_calls
, 0, sizeof(ime_calls
) );
4428 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_STARTCOMPOSITION
, 0, 0 ) );
4429 ok_seq( start_composition_seq
);
4430 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_ENDCOMPOSITION
, 0, 0 ) );
4431 ok_seq( end_composition_seq
);
4432 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_COMPOSITION
, 0, 0 ) );
4433 ok_seq( composition_seq
);
4434 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_SETCONTEXT
, 0, 0 ) );
4435 ok_seq( set_context_seq
);
4436 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_NOTIFY
, 0, 0 ) );
4437 ok_seq( notify_seq
);
4438 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_CONTROL
, 0, 0 ) );
4439 ok_seq( empty_sequence
);
4440 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_COMPOSITIONFULL
, 0, 0 ) );
4441 ok_seq( empty_sequence
);
4442 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_SELECT
, 0, 0 ) );
4443 ok_seq( empty_sequence
);
4444 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_CHAR
, 0, 0 ) );
4445 ok_seq( empty_sequence
);
4446 ok_ret( 0, DefWindowProcW( hwnd
, 0x287, 0, 0 ) );
4447 ok_seq( empty_sequence
);
4448 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_REQUEST
, 0, 0 ) );
4449 ok_seq( empty_sequence
);
4450 ret
= DefWindowProcW( hwnd
, WM_IME_KEYDOWN
, 0, 0 );
4453 ok_seq( empty_sequence
);
4454 ret
= DefWindowProcW( hwnd
, WM_IME_KEYUP
, 0, 0 );
4457 ok_seq( empty_sequence
);
4459 ok_ret( 1, ImmActivateLayout( old_hkl
) );
4460 ok_ret( 1, DestroyWindow( hwnd
) );
4463 ime_cleanup( hkl
, TRUE
);
4464 memset( ime_calls
, 0, sizeof(ime_calls
) );
4470 default_hkl
= GetKeyboardLayout( 0 );
4472 if (!is_ime_enabled())
4474 win_skip("IME support not implemented\n");
4478 test_com_initialization();
4480 test_ImmEnumInputContext();
4482 test_ImmInstallIME();
4483 test_ImmGetDescription();
4484 test_ImmGetIMEFileName();
4486 test_ImmGetProperty();
4488 test_ImmEscape( FALSE
);
4489 test_ImmEscape( TRUE
);
4490 test_ImmEnumRegisterWord( FALSE
);
4491 test_ImmEnumRegisterWord( TRUE
);
4492 test_ImmRegisterWord( FALSE
);
4493 test_ImmRegisterWord( TRUE
);
4494 test_ImmGetRegisterWordStyle( FALSE
);
4495 test_ImmGetRegisterWordStyle( TRUE
);
4496 test_ImmUnregisterWord( FALSE
);
4497 test_ImmUnregisterWord( TRUE
);
4499 test_ImmActivateLayout();
4500 test_ImmCreateInputContext();
4501 test_ImmProcessKey();
4502 test_DefWindowProc();
4506 test_ImmNotifyIME();
4507 test_ImmGetCompositionString();
4508 test_ImmSetCompositionString();
4510 test_ImmAssociateContextEx();
4511 test_NtUserAssociateInputContext();
4513 test_ImmIsUIMessage();
4514 test_ImmGetContext();
4515 test_ImmDefaultHwnd();
4516 test_default_ime_window_creation();
4517 test_ImmGetIMCLockCount();
4518 test_ImmGetIMCCLockCount();
4519 test_ImmDestroyContext();
4520 test_ImmDestroyIMCC();
4523 /* Reinitialize the hooks to capture all windows */
4528 test_ime_processkey();
4529 else win_skip("SendInput is not available\n");
4531 /* there's no way of enabling IME - keep the test last */
4532 test_ImmDisableIME();