wineps: Copy GetTextExtentExPoint implementation to unixlib.
[wine.git] / dlls / imm32 / imm.c
blob2fe355da5bb699c773dec26dc712884fc54d7910
1 /*
2 * IMM32 library
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #include "initguid.h"
24 #include "imm_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(imm);
28 #define IMM_INIT_MAGIC 0x19650412
29 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
31 HMODULE imm32_module;
33 /* MSIME messages */
34 UINT WM_MSIME_SERVICE;
35 UINT WM_MSIME_RECONVERTOPTIONS;
36 UINT WM_MSIME_MOUSE;
37 UINT WM_MSIME_RECONVERTREQUEST;
38 UINT WM_MSIME_RECONVERT;
39 UINT WM_MSIME_QUERYPOSITION;
40 UINT WM_MSIME_DOCUMENTFEED;
42 struct imc_entry
44 HIMC himc;
45 INPUTCONTEXT context;
46 struct list entry;
49 struct ime
51 LONG refcount; /* guarded by ime_cs */
53 HKL hkl;
54 HMODULE module;
55 struct list entry;
57 IMEINFO info;
58 WCHAR ui_class[17];
59 struct list input_contexts;
61 BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD);
62 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
63 BOOL (WINAPI *pImeDestroy)(UINT);
64 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
65 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
66 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
67 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, TRANSMSGLIST *, UINT, HIMC);
68 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
69 BOOL (WINAPI *pImeRegisterWord)(const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*);
70 BOOL (WINAPI *pImeUnregisterWord)(const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*);
71 UINT (WINAPI *pImeEnumRegisterWord)(void */*REGISTERWORDENUMPROCW*/, const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*, void *);
72 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*, DWORD);
73 DWORD (WINAPI *pImeConversionList)(HIMC, const void/*TCHAR*/*, CANDIDATELIST*, DWORD, UINT);
74 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, void/*STYLEBUFW*/*);
75 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE*);
76 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, void/*IMEMENUITEMINFOW*/*, void/*IMEMENUITEMINFOW*/*, DWORD);
79 static HRESULT (WINAPI *pCoRevokeInitializeSpy)(ULARGE_INTEGER cookie);
80 static void (WINAPI *pCoUninitialize)(void);
82 struct imc
84 HIMC handle;
85 DWORD dwLock;
86 INPUTCONTEXT IMC;
88 struct ime *ime;
89 UINT vkey;
91 HWND ui_hwnd; /* IME UI window, on the default input context */
94 #define WINE_IMC_VALID_MAGIC 0x56434D49
96 struct coinit_spy
98 IInitializeSpy IInitializeSpy_iface;
99 LONG ref;
100 ULARGE_INTEGER cookie;
101 enum
103 IMM_APT_INIT = 0x1,
104 IMM_APT_CREATED = 0x2,
105 IMM_APT_CAN_FREE = 0x4,
106 IMM_APT_BROKEN = 0x8
107 } apt_flags;
110 static CRITICAL_SECTION ime_cs;
111 static CRITICAL_SECTION_DEBUG ime_cs_debug =
113 0, 0, &ime_cs,
114 { &ime_cs_debug.ProcessLocksList, &ime_cs_debug.ProcessLocksList },
115 0, 0, { (DWORD_PTR)(__FILE__ ": ime_cs") }
117 static CRITICAL_SECTION ime_cs = { &ime_cs_debug, -1, 0, 0, 0, 0 };
118 static struct list ime_list = LIST_INIT( ime_list );
120 static const WCHAR layouts_formatW[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
122 static const char *debugstr_composition( const COMPOSITIONFORM *composition )
124 if (!composition) return "(null)";
125 return wine_dbg_sprintf( "style %#lx, pos %s, area %s", composition->dwStyle,
126 wine_dbgstr_point( &composition->ptCurrentPos ),
127 wine_dbgstr_rect( &composition->rcArea ) );
130 static const char *debugstr_candidate( const CANDIDATEFORM *candidate )
132 if (!candidate) return "(null)";
133 return wine_dbg_sprintf( "idx %#lx, style %#lx, pos %s, area %s", candidate->dwIndex,
134 candidate->dwStyle, wine_dbgstr_point( &candidate->ptCurrentPos ),
135 wine_dbgstr_rect( &candidate->rcArea ) );
138 static BOOL ime_is_unicode( const struct ime *ime )
140 return !!(ime->info.fdwProperty & IME_PROP_UNICODE);
143 static BOOL input_context_is_unicode( INPUTCONTEXT *ctx )
145 struct imc *imc = CONTAINING_RECORD( ctx, struct imc, IMC );
146 return !imc->ime || ime_is_unicode( imc->ime );
149 static BOOL IMM_DestroyContext(HIMC hIMC);
150 static struct imc *get_imc_data( HIMC hIMC );
152 static inline WCHAR *strdupAtoW( const char *str )
154 WCHAR *ret = NULL;
155 if (str)
157 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
158 if ((ret = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
160 return ret;
163 static inline CHAR *strdupWtoA( const WCHAR *str )
165 CHAR *ret = NULL;
166 if (str)
168 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
169 if ((ret = malloc( len ))) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
171 return ret;
174 static DWORD convert_candidatelist_WtoA(
175 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
177 DWORD ret, i, len;
179 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
180 if ( lpDst && dwBufLen > 0 )
182 *lpDst = *lpSrc;
183 lpDst->dwOffset[0] = ret;
186 for ( i = 0; i < lpSrc->dwCount; i++)
188 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
190 if ( lpDst && dwBufLen > 0 )
192 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
194 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
195 (LPSTR)dest, dwBufLen, NULL, NULL);
197 if ( i + 1 < lpSrc->dwCount )
198 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
199 dwBufLen -= len * sizeof(char);
201 else
202 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
204 ret += len * sizeof(char);
207 if ( lpDst )
208 lpDst->dwSize = ret;
210 return ret;
213 static DWORD convert_candidatelist_AtoW(
214 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
216 DWORD ret, i, len;
218 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
219 if ( lpDst && dwBufLen > 0 )
221 *lpDst = *lpSrc;
222 lpDst->dwOffset[0] = ret;
225 for ( i = 0; i < lpSrc->dwCount; i++)
227 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
229 if ( lpDst && dwBufLen > 0 )
231 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
233 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
234 (LPWSTR)dest, dwBufLen);
236 if ( i + 1 < lpSrc->dwCount )
237 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
238 dwBufLen -= len * sizeof(WCHAR);
240 else
241 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
243 ret += len * sizeof(WCHAR);
246 if ( lpDst )
247 lpDst->dwSize = ret;
249 return ret;
252 static struct coinit_spy *get_thread_coinit_spy(void)
254 return (struct coinit_spy *)(UINT_PTR)NtUserGetThreadInfo()->client_imm;
257 static void imm_couninit_thread(BOOL cleanup)
259 struct coinit_spy *spy;
261 TRACE("implicit COM deinitialization\n");
263 if (!(spy = get_thread_coinit_spy()) || (spy->apt_flags & IMM_APT_BROKEN))
264 return;
266 if (cleanup && spy->cookie.QuadPart)
268 pCoRevokeInitializeSpy(spy->cookie);
269 spy->cookie.QuadPart = 0;
272 if (!(spy->apt_flags & IMM_APT_INIT))
273 return;
274 spy->apt_flags &= ~IMM_APT_INIT;
276 if (spy->apt_flags & IMM_APT_CREATED)
278 spy->apt_flags &= ~IMM_APT_CREATED;
279 if (spy->apt_flags & IMM_APT_CAN_FREE)
280 pCoUninitialize();
282 if (cleanup)
283 spy->apt_flags = 0;
286 static inline struct coinit_spy *impl_from_IInitializeSpy(IInitializeSpy *iface)
288 return CONTAINING_RECORD(iface, struct coinit_spy, IInitializeSpy_iface);
291 static HRESULT WINAPI InitializeSpy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj)
293 if (IsEqualIID(&IID_IInitializeSpy, riid) ||
294 IsEqualIID(&IID_IUnknown, riid))
296 *obj = iface;
297 IInitializeSpy_AddRef(iface);
298 return S_OK;
301 *obj = NULL;
302 return E_NOINTERFACE;
305 static ULONG WINAPI InitializeSpy_AddRef(IInitializeSpy *iface)
307 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
308 return InterlockedIncrement(&spy->ref);
311 static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface)
313 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
314 LONG ref = InterlockedDecrement(&spy->ref);
315 if (!ref)
317 free( spy );
318 NtUserGetThreadInfo()->client_imm = 0;
320 return ref;
323 static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
324 DWORD coinit, DWORD refs)
326 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
328 if ((spy->apt_flags & IMM_APT_CREATED) &&
329 !(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
331 imm_couninit_thread(TRUE);
332 spy->apt_flags |= IMM_APT_BROKEN;
334 return S_OK;
337 static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
338 HRESULT hr, DWORD coinit, DWORD refs)
340 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
342 if ((spy->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
343 hr = S_OK;
344 if (SUCCEEDED(hr))
345 spy->apt_flags |= IMM_APT_CAN_FREE;
346 return hr;
349 static HRESULT WINAPI InitializeSpy_PreUninitialize(IInitializeSpy *iface, DWORD refs)
351 return S_OK;
354 static HRESULT WINAPI InitializeSpy_PostUninitialize(IInitializeSpy *iface, DWORD refs)
356 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
358 TRACE("%lu %p\n", refs, ImmGetDefaultIMEWnd(0));
360 if (refs == 1 && !ImmGetDefaultIMEWnd(0))
361 imm_couninit_thread(FALSE);
362 else if (!refs)
363 spy->apt_flags &= ~IMM_APT_CAN_FREE;
364 return S_OK;
367 static const IInitializeSpyVtbl InitializeSpyVtbl =
369 InitializeSpy_QueryInterface,
370 InitializeSpy_AddRef,
371 InitializeSpy_Release,
372 InitializeSpy_PreInitialize,
373 InitializeSpy_PostInitialize,
374 InitializeSpy_PreUninitialize,
375 InitializeSpy_PostUninitialize,
378 static BOOL WINAPI init_ole32_funcs( INIT_ONCE *once, void *param, void **context )
380 HMODULE module_ole32 = GetModuleHandleA("ole32");
381 pCoRevokeInitializeSpy = (void*)GetProcAddress(module_ole32, "CoRevokeInitializeSpy");
382 pCoUninitialize = (void*)GetProcAddress(module_ole32, "CoUninitialize");
383 return TRUE;
386 static void imm_coinit_thread(void)
388 struct coinit_spy *spy;
389 HRESULT hr;
390 static INIT_ONCE init_ole32_once = INIT_ONCE_STATIC_INIT;
392 TRACE("implicit COM initialization\n");
394 if (!(spy = get_thread_coinit_spy()))
396 if (!(spy = malloc( sizeof(*spy) ))) return;
397 spy->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
398 spy->ref = 1;
399 spy->cookie.QuadPart = 0;
400 spy->apt_flags = 0;
401 NtUserGetThreadInfo()->client_imm = (UINT_PTR)spy;
405 if (spy->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
406 return;
407 spy->apt_flags |= IMM_APT_INIT;
409 if(!spy->cookie.QuadPart)
411 hr = CoRegisterInitializeSpy(&spy->IInitializeSpy_iface, &spy->cookie);
412 if (FAILED(hr))
413 return;
416 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
417 if (SUCCEEDED(hr))
418 spy->apt_flags |= IMM_APT_CREATED;
420 InitOnceExecuteOnce(&init_ole32_once, init_ole32_funcs, NULL, NULL);
423 static struct imc *query_imc_data( HIMC handle )
425 struct imc *ret;
427 if (!handle) return NULL;
428 ret = (void *)NtUserQueryInputContext(handle, NtUserInputContextClientPtr);
429 return ret && ret->handle == handle ? ret : NULL;
432 static HMODULE load_graphics_driver(void)
434 static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{";
435 static const WCHAR displayW[] = L"}\\0000";
437 HMODULE ret = 0;
438 HKEY hkey;
439 DWORD size;
440 WCHAR path[MAX_PATH];
441 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
442 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" ));
444 if (!guid_atom) return 0;
445 memcpy( key, key_pathW, sizeof(key_pathW) );
446 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
447 lstrcatW( key, displayW );
448 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
449 size = sizeof(path);
450 if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size ))
451 ret = LoadLibraryW( path );
452 RegCloseKey( hkey );
453 TRACE( "%s %p\n", debugstr_w(path), ret );
454 return ret;
457 /* lookup an IME from a HKL, must hold ime_cs */
458 static struct ime *find_ime_from_hkl( HKL hkl )
460 struct ime *ime = NULL;
461 LIST_FOR_EACH_ENTRY( ime, &ime_list, struct ime, entry )
462 if (ime->hkl == hkl) return ime;
463 return NULL;
466 BOOL WINAPI ImmFreeLayout( HKL hkl )
468 struct imc_entry *imc_entry, *imc_next;
469 struct ime *ime;
471 TRACE( "hkl %p\n", hkl );
473 EnterCriticalSection( &ime_cs );
474 if ((ime = find_ime_from_hkl( hkl )))
476 list_remove( &ime->entry );
477 if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" );
478 LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry )
480 ImmDestroyIMCC( imc_entry->context.hPrivate );
481 free( imc_entry );
484 LeaveCriticalSection( &ime_cs );
485 if (!ime) return TRUE;
487 FreeLibrary( ime->module );
488 free( ime );
489 return TRUE;
492 BOOL WINAPI ImmLoadIME( HKL hkl )
494 WCHAR buffer[MAX_PATH] = {0};
495 BOOL use_default_ime;
496 struct ime *ime;
498 TRACE( "hkl %p\n", hkl );
500 EnterCriticalSection( &ime_cs );
501 if ((ime = find_ime_from_hkl( hkl )) || !(ime = calloc( 1, sizeof(*ime) )))
503 LeaveCriticalSection( &ime_cs );
504 return !!ime;
507 if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) use_default_ime = TRUE;
508 else if (!(ime->module = LoadLibraryW( buffer ))) use_default_ime = TRUE;
509 else use_default_ime = FALSE;
511 if (use_default_ime)
513 if (*buffer) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer) );
514 if (!(ime->module = load_graphics_driver())) ime->module = LoadLibraryW( L"imm32" );
517 #define LOAD_FUNCPTR( f ) \
518 if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \
519 !(ime->p##f = use_default_ime ? (void *)f : NULL)) \
521 LeaveCriticalSection( &ime_cs ); \
522 WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \
523 goto failed; \
525 LOAD_FUNCPTR( ImeInquire );
526 LOAD_FUNCPTR( ImeDestroy );
527 LOAD_FUNCPTR( ImeSelect );
528 LOAD_FUNCPTR( ImeConfigure );
529 LOAD_FUNCPTR( ImeEscape );
530 LOAD_FUNCPTR( ImeSetActiveContext );
531 LOAD_FUNCPTR( ImeToAsciiEx );
532 LOAD_FUNCPTR( NotifyIME );
533 LOAD_FUNCPTR( ImeRegisterWord );
534 LOAD_FUNCPTR( ImeUnregisterWord );
535 LOAD_FUNCPTR( ImeEnumRegisterWord );
536 LOAD_FUNCPTR( ImeSetCompositionString );
537 LOAD_FUNCPTR( ImeConversionList );
538 LOAD_FUNCPTR( ImeProcessKey );
539 LOAD_FUNCPTR( ImeGetRegisterWordStyle );
540 LOAD_FUNCPTR( ImeGetImeMenuItems );
541 #undef LOAD_FUNCPTR
543 ime->hkl = hkl;
544 if (!ime->pImeInquire( &ime->info, buffer, 0 ))
546 LeaveCriticalSection( &ime_cs );
547 goto failed;
550 if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) );
551 else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) );
552 list_init( &ime->input_contexts );
554 list_add_tail( &ime_list, &ime->entry );
555 LeaveCriticalSection( &ime_cs );
557 TRACE( "Created IME %p for HKL %p\n", ime, hkl );
558 return TRUE;
560 failed:
561 if (ime->module) FreeLibrary( ime->module );
562 free( ime );
563 return FALSE;
566 static struct ime *ime_acquire( HKL hkl )
568 struct ime *ime;
570 EnterCriticalSection( &ime_cs );
572 if (!ImmLoadIME( hkl )) ime = NULL;
573 else ime = find_ime_from_hkl( hkl );
575 if (ime)
577 ULONG ref = ++ime->refcount;
578 TRACE( "ime %p increasing refcount to %lu.\n", ime, ref );
581 LeaveCriticalSection( &ime_cs );
583 return ime;
586 static void ime_release( struct ime *ime )
588 ULONG ref;
590 EnterCriticalSection( &ime_cs );
592 ref = --ime->refcount;
593 TRACE( "ime %p decreasing refcount to %lu.\n", ime, ref );
595 if (!ref && (ime->info.fdwProperty & IME_PROP_END_UNLOAD))
596 ImmFreeLayout( ime->hkl );
598 LeaveCriticalSection( &ime_cs );
601 static void ime_save_input_context( struct ime *ime, HIMC himc, INPUTCONTEXT *ctx )
603 static INPUTCONTEXT default_input_context =
605 .cfCandForm = {{.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}}
607 const INPUTCONTEXT old = *ctx;
608 struct imc_entry *entry;
610 *ctx = default_input_context;
611 ctx->hWnd = old.hWnd;
612 ctx->hMsgBuf = old.hMsgBuf;
613 ctx->hCompStr = old.hCompStr;
614 ctx->hCandInfo = old.hCandInfo;
615 ctx->hGuideLine = old.hGuideLine;
616 if (!(ctx->hPrivate = ImmCreateIMCC( ime->info.dwPrivateDataSize )))
617 WARN( "Failed to allocate IME private data\n" );
619 if (!(entry = malloc( sizeof(*entry) ))) return;
620 entry->himc = himc;
621 entry->context = *ctx;
623 EnterCriticalSection( &ime_cs );
625 /* reference the IME the first time the input context cache is used
626 * in the same way Windows does it, so it doesn't get destroyed and
627 * INPUTCONTEXT cache lost when keyboard layout is changed
629 if (list_empty( &ime->input_contexts )) ime->refcount++;
631 list_add_tail( &ime->input_contexts, &entry->entry );
632 LeaveCriticalSection( &ime_cs );
635 static INPUTCONTEXT *ime_find_input_context( struct ime *ime, HIMC himc )
637 struct imc_entry *entry;
639 EnterCriticalSection( &ime_cs );
640 LIST_FOR_EACH_ENTRY( entry, &ime->input_contexts, struct imc_entry, entry )
641 if (entry->himc == himc) break;
642 LeaveCriticalSection( &ime_cs );
644 if (&entry->entry == &ime->input_contexts) return NULL;
645 return &entry->context;
648 static void imc_release_ime( struct imc *imc, struct ime *ime )
650 INPUTCONTEXT *ctx;
652 if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd );
653 imc->ui_hwnd = NULL;
654 ime->pImeSelect( imc->handle, FALSE );
656 if ((ctx = ime_find_input_context( ime, imc->handle ))) *ctx = imc->IMC;
657 ime_release( ime );
660 static struct ime *imc_select_ime( struct imc *imc )
662 HKL hkl = GetKeyboardLayout( 0 );
663 struct ime *ime;
665 if ((ime = imc->ime))
667 if (ime->hkl == hkl) return ime;
668 imc->ime = NULL;
669 imc_release_ime( imc, ime );
672 if (!(imc->ime = ime_acquire( hkl )))
673 WARN( "Failed to acquire IME for HKL %p\n", hkl );
674 else
676 INPUTCONTEXT *ctx;
678 if ((ctx = ime_find_input_context( imc->ime, imc->handle ))) imc->IMC = *ctx;
679 else ime_save_input_context( imc->ime, imc->handle, &imc->IMC );
681 imc->ime->pImeSelect( imc->handle, TRUE );
684 return imc->ime;
687 static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam )
689 if (ImmLockIMC( himc )) ImmUnlockIMC( himc );
690 return TRUE;
693 BOOL WINAPI ImmActivateLayout( HKL hkl )
695 TRACE( "hkl %p\n", hkl );
697 if (hkl == GetKeyboardLayout( 0 )) return TRUE;
698 if (!ActivateKeyboardLayout( hkl, 0 )) return FALSE;
700 ImmEnumInputContext( 0, enum_activate_layout, 0 );
702 return TRUE;
705 static BOOL free_input_context_data( HIMC hIMC )
707 struct imc *data = query_imc_data( hIMC );
708 struct ime *ime;
710 if (!data) return FALSE;
712 TRACE( "Destroying %p\n", hIMC );
714 if ((ime = imc_select_ime( data ))) imc_release_ime( data, ime );
716 ImmDestroyIMCC( data->IMC.hCompStr );
717 ImmDestroyIMCC( data->IMC.hCandInfo );
718 ImmDestroyIMCC( data->IMC.hGuideLine );
719 ImmDestroyIMCC( data->IMC.hMsgBuf );
721 free( data );
723 return TRUE;
726 static void input_context_init( INPUTCONTEXT *ctx )
728 COMPOSITIONSTRING *str;
729 CANDIDATEINFO *info;
730 GUIDELINE *line;
731 UINT i;
733 if (!(ctx->hMsgBuf = ImmCreateIMCC( 0 )))
734 WARN( "Failed to allocate %p message buffer\n", ctx );
736 if (!(ctx->hCompStr = ImmCreateIMCC( sizeof(COMPOSITIONSTRING) )))
737 WARN( "Failed to allocate %p COMPOSITIONSTRING\n", ctx );
738 else if (!(str = ImmLockIMCC( ctx->hCompStr )))
739 WARN( "Failed to lock IMCC for COMPOSITIONSTRING\n" );
740 else
742 str->dwSize = sizeof(COMPOSITIONSTRING);
743 ImmUnlockIMCC( ctx->hCompStr );
746 if (!(ctx->hCandInfo = ImmCreateIMCC( sizeof(CANDIDATEINFO) )))
747 WARN( "Failed to allocate %p CANDIDATEINFO\n", ctx );
748 else if (!(info = ImmLockIMCC( ctx->hCandInfo )))
749 WARN( "Failed to lock IMCC for CANDIDATEINFO\n" );
750 else
752 info->dwSize = sizeof(CANDIDATEINFO);
753 ImmUnlockIMCC( ctx->hCandInfo );
756 if (!(ctx->hGuideLine = ImmCreateIMCC( sizeof(GUIDELINE) )))
757 WARN( "Failed to allocate %p GUIDELINE\n", ctx );
758 else if (!(line = ImmLockIMCC( ctx->hGuideLine )))
759 WARN( "Failed to lock IMCC for GUIDELINE\n" );
760 else
762 line->dwSize = sizeof(GUIDELINE);
763 ImmUnlockIMCC( ctx->hGuideLine );
766 for (i = 0; i < ARRAY_SIZE(ctx->cfCandForm); i++)
767 ctx->cfCandForm[i].dwIndex = ~0u;
770 static void IMM_FreeThreadData(void)
772 struct coinit_spy *spy;
774 free_input_context_data( UlongToHandle( NtUserGetThreadInfo()->default_imc ) );
775 if ((spy = get_thread_coinit_spy())) IInitializeSpy_Release( &spy->IInitializeSpy_iface );
778 static void IMM_FreeAllImmHkl(void)
780 struct ime *ime, *ime_next;
782 LIST_FOR_EACH_ENTRY_SAFE( ime, ime_next, &ime_list, struct ime, entry )
784 struct imc_entry *imc_entry, *imc_next;
785 list_remove( &ime->entry );
787 ime->pImeDestroy( 1 );
788 FreeLibrary( ime->module );
789 LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry )
791 ImmDestroyIMCC( imc_entry->context.hPrivate );
792 free( imc_entry );
795 free( ime );
799 BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
801 TRACE( "instance %p, reason %lx, reserved %p\n", instance, reason, reserved );
803 switch (reason)
805 case DLL_PROCESS_ATTACH:
806 if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE;
807 imm32_module = instance;
808 break;
809 case DLL_THREAD_ATTACH:
810 break;
811 case DLL_THREAD_DETACH:
812 IMM_FreeThreadData();
813 break;
814 case DLL_PROCESS_DETACH:
815 if (reserved) break;
816 IMM_FreeThreadData();
817 IMM_FreeAllImmHkl();
818 break;
821 return TRUE;
824 /***********************************************************************
825 * ImmSetActiveContext (IMM32.@)
827 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
829 struct imc *data = get_imc_data( himc );
830 struct ime *ime;
832 TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
834 if (himc && !data && activate)
835 return FALSE;
837 imm_coinit_thread();
839 if (data)
841 if (activate) data->IMC.hWnd = hwnd;
842 if ((ime = imc_select_ime( data ))) ime->pImeSetActiveContext( himc, activate );
845 if (IsWindow(hwnd))
847 SendMessageW(hwnd, WM_IME_SETCONTEXT, activate, ISC_SHOWUIALL);
848 /* TODO: send WM_IME_NOTIFY */
850 SetLastError(0);
851 return TRUE;
854 /***********************************************************************
855 * ImmConfigureIMEA (IMM32.@)
857 BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data )
859 struct ime *ime;
860 BOOL ret;
862 TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data );
864 if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE;
865 if (!(ime = ime_acquire( hkl ))) return FALSE;
867 if (mode != IME_CONFIG_REGISTERWORD || !ime_is_unicode( ime ))
868 ret = ime->pImeConfigure( hkl, hwnd, mode, data );
869 else
871 REGISTERWORDA *wordA = data;
872 REGISTERWORDW wordW;
873 wordW.lpWord = strdupAtoW( wordA->lpWord );
874 wordW.lpReading = strdupAtoW( wordA->lpReading );
875 ret = ime->pImeConfigure( hkl, hwnd, mode, &wordW );
876 free( wordW.lpReading );
877 free( wordW.lpWord );
880 ime_release( ime );
881 return ret;
884 /***********************************************************************
885 * ImmConfigureIMEW (IMM32.@)
887 BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data )
889 struct ime *ime;
890 BOOL ret;
892 TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data );
894 if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE;
895 if (!(ime = ime_acquire( hkl ))) return FALSE;
897 if (mode != IME_CONFIG_REGISTERWORD || ime_is_unicode( ime ))
898 ret = ime->pImeConfigure( hkl, hwnd, mode, data );
899 else
901 REGISTERWORDW *wordW = data;
902 REGISTERWORDA wordA;
903 wordA.lpWord = strdupWtoA( wordW->lpWord );
904 wordA.lpReading = strdupWtoA( wordW->lpReading );
905 ret = ime->pImeConfigure( hkl, hwnd, mode, &wordA );
906 free( wordA.lpReading );
907 free( wordA.lpWord );
910 ime_release( ime );
911 return ret;
914 static struct imc *create_input_context( HIMC default_imc )
916 struct imc *new_context;
918 if (!(new_context = calloc( 1, sizeof(*new_context) ))) return NULL;
919 input_context_init( &new_context->IMC );
921 if (!default_imc)
922 new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context);
923 else if (NtUserUpdateInputContext(default_imc, NtUserInputContextClientPtr, (UINT_PTR)new_context))
924 new_context->handle = default_imc;
925 if (!new_context->handle)
927 free_input_context_data(new_context);
928 return 0;
931 TRACE("Created context %p\n", new_context);
932 return new_context;
935 static struct imc *get_imc_data( HIMC handle )
937 struct imc *ret;
939 if ((ret = query_imc_data(handle)) || !handle) return ret;
940 return create_input_context(handle);
943 static struct imc *default_input_context(void)
945 UINT *himc = &NtUserGetThreadInfo()->default_imc;
946 if (!*himc) *himc = (UINT_PTR)NtUserCreateInputContext( 0 );
947 return get_imc_data( (HIMC)(UINT_PTR)*himc );
950 static HWND get_ime_ui_window(void)
952 struct imc *imc = default_input_context();
953 struct ime *ime;
955 if (!(ime = imc_select_ime( imc ))) return 0;
957 if (!imc->ui_hwnd)
959 imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1,
960 ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 );
961 SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)NtUserGetWindowInputContext( GetFocus() ) );
963 return imc->ui_hwnd;
966 static void set_ime_ui_window_himc( HIMC himc )
968 HWND hwnd;
969 if (!(hwnd = get_ime_ui_window())) return;
970 SetWindowLongPtrW( hwnd, IMMGWL_IMC, (LONG_PTR)himc );
973 /***********************************************************************
974 * ImmCreateContext (IMM32.@)
976 HIMC WINAPI ImmCreateContext(void)
978 struct imc *new_context;
980 if (!(new_context = create_input_context(0))) return 0;
981 return new_context->handle;
984 static BOOL IMM_DestroyContext(HIMC hIMC)
986 if (!free_input_context_data(hIMC)) return FALSE;
987 NtUserDestroyInputContext(hIMC);
988 return TRUE;
991 /***********************************************************************
992 * ImmDestroyContext (IMM32.@)
994 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
996 if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE;
997 if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
998 return IMM_DestroyContext(hIMC);
1001 /***********************************************************************
1002 * ImmAssociateContext (IMM32.@)
1004 HIMC WINAPI ImmAssociateContext( HWND hwnd, HIMC new_himc )
1006 HIMC old_himc;
1007 UINT ret;
1009 TRACE( "hwnd %p, new_himc %p\n", hwnd, new_himc );
1011 old_himc = NtUserGetWindowInputContext( hwnd );
1012 ret = NtUserAssociateInputContext( hwnd, new_himc, 0 );
1013 if (ret == AICR_FOCUS_CHANGED)
1015 ImmSetActiveContext( hwnd, old_himc, FALSE );
1016 ImmSetActiveContext( hwnd, new_himc, TRUE );
1017 if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc );
1020 return ret == AICR_FAILED ? 0 : old_himc;
1023 static BOOL CALLBACK enum_associate_context( HWND hwnd, LPARAM lparam )
1025 ImmAssociateContext( hwnd, (HIMC)lparam );
1026 return TRUE;
1029 /***********************************************************************
1030 * ImmAssociateContextEx (IMM32.@)
1032 BOOL WINAPI ImmAssociateContextEx( HWND hwnd, HIMC new_himc, DWORD flags )
1034 HIMC old_himc;
1035 UINT ret;
1037 TRACE( "hwnd %p, new_himc %p, flags %#lx\n", hwnd, new_himc, flags );
1039 if (!hwnd) return FALSE;
1041 if (flags == IACE_CHILDREN)
1043 EnumChildWindows( hwnd, enum_associate_context, (LPARAM)new_himc );
1044 return TRUE;
1047 old_himc = NtUserGetWindowInputContext( hwnd );
1048 ret = NtUserAssociateInputContext( hwnd, new_himc, flags );
1049 if (ret == AICR_FOCUS_CHANGED)
1051 ImmSetActiveContext( hwnd, old_himc, FALSE );
1052 ImmSetActiveContext( hwnd, new_himc, TRUE );
1053 if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc );
1056 return ret != AICR_FAILED;
1059 struct enum_register_word_params_WtoA
1061 REGISTERWORDENUMPROCA proc;
1062 void *user;
1065 static int CALLBACK enum_register_word_WtoA( const WCHAR *readingW, DWORD style,
1066 const WCHAR *stringW, void *user )
1068 char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
1069 struct enum_register_word_params_WtoA *params = user;
1070 int ret = params->proc( readingA, style, stringA, params->user );
1071 free( readingA );
1072 free( stringA );
1073 return ret;
1076 /***********************************************************************
1077 * ImmEnumRegisterWordA (IMM32.@)
1079 UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const char *readingA,
1080 DWORD style, const char *stringA, void *user )
1082 struct ime *ime;
1083 UINT ret;
1085 TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl, procA,
1086 debugstr_a(readingA), style, debugstr_a(stringA), user );
1088 if (!(ime = ime_acquire( hkl ))) return 0;
1090 if (!ime_is_unicode( ime ))
1091 ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user );
1092 else
1094 struct enum_register_word_params_WtoA params = {.proc = procA, .user = user};
1095 WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
1096 ret = ime->pImeEnumRegisterWord( enum_register_word_WtoA, readingW, style, stringW, &params );
1097 free( readingW );
1098 free( stringW );
1101 ime_release( ime );
1102 return ret;
1105 struct enum_register_word_params_AtoW
1107 REGISTERWORDENUMPROCW proc;
1108 void *user;
1111 static int CALLBACK enum_register_word_AtoW( const char *readingA, DWORD style,
1112 const char *stringA, void *user )
1114 WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
1115 struct enum_register_word_params_AtoW *params = user;
1116 int ret = params->proc( readingW, style, stringW, params->user );
1117 free( readingW );
1118 free( stringW );
1119 return ret;
1122 /***********************************************************************
1123 * ImmEnumRegisterWordW (IMM32.@)
1125 UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WCHAR *readingW,
1126 DWORD style, const WCHAR *stringW, void *user )
1128 struct ime *ime;
1129 UINT ret;
1131 TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl, procW,
1132 debugstr_w(readingW), style, debugstr_w(stringW), user );
1134 if (!(ime = ime_acquire( hkl ))) return 0;
1136 if (ime_is_unicode( ime ))
1137 ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user );
1138 else
1140 struct enum_register_word_params_AtoW params = {.proc = procW, .user = user};
1141 char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
1142 ret = ime->pImeEnumRegisterWord( enum_register_word_AtoW, readingA, style, stringA, &params );
1143 free( readingA );
1144 free( stringA );
1147 ime_release( ime );
1148 return ret;
1151 static inline BOOL EscapeRequiresWA(UINT uEscape)
1153 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
1154 uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
1155 uEscape == IME_ESC_IME_NAME ||
1156 uEscape == IME_ESC_GETHELPFILENAME)
1157 return TRUE;
1158 return FALSE;
1161 /***********************************************************************
1162 * ImmEscapeA (IMM32.@)
1164 LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data )
1166 struct ime *ime;
1167 LRESULT ret;
1169 TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data );
1171 if (!(ime = ime_acquire( hkl ))) return 0;
1173 if (!EscapeRequiresWA( code ) || !ime_is_unicode( ime ) || !data)
1174 ret = ime->pImeEscape( himc, code, data );
1175 else
1177 WCHAR buffer[81]; /* largest required buffer should be 80 */
1178 if (code == IME_ESC_SET_EUDC_DICTIONARY)
1180 MultiByteToWideChar( CP_ACP, 0, data, -1, buffer, 81 );
1181 ret = ime->pImeEscape( himc, code, buffer );
1183 else
1185 ret = ime->pImeEscape( himc, code, buffer );
1186 WideCharToMultiByte( CP_ACP, 0, buffer, -1, data, 80, NULL, NULL );
1190 ime_release( ime );
1191 return ret;
1194 /***********************************************************************
1195 * ImmEscapeW (IMM32.@)
1197 LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data )
1199 struct ime *ime;
1200 LRESULT ret;
1202 TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data );
1204 if (!(ime = ime_acquire( hkl ))) return 0;
1206 if (!EscapeRequiresWA( code ) || ime_is_unicode( ime ) || !data)
1207 ret = ime->pImeEscape( himc, code, data );
1208 else
1210 char buffer[81]; /* largest required buffer should be 80 */
1211 if (code == IME_ESC_SET_EUDC_DICTIONARY)
1213 WideCharToMultiByte( CP_ACP, 0, data, -1, buffer, 81, NULL, NULL );
1214 ret = ime->pImeEscape( himc, code, buffer );
1216 else
1218 ret = ime->pImeEscape( himc, code, buffer );
1219 MultiByteToWideChar( CP_ACP, 0, buffer, -1, data, 80 );
1223 ime_release( ime );
1224 return ret;
1227 /***********************************************************************
1228 * ImmGetCandidateListA (IMM32.@)
1230 DWORD WINAPI ImmGetCandidateListA(
1231 HIMC hIMC, DWORD dwIndex,
1232 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1234 struct imc *data = get_imc_data( hIMC );
1235 LPCANDIDATEINFO candinfo;
1236 LPCANDIDATELIST candlist;
1237 struct ime *ime;
1238 DWORD ret = 0;
1240 TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
1242 if (!data || !data->IMC.hCandInfo)
1243 return 0;
1245 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1246 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1247 goto done;
1249 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1250 if ( !candlist->dwSize || !candlist->dwCount )
1251 goto done;
1253 if (!(ime = imc_select_ime( data )))
1254 ret = 0;
1255 else if (!ime_is_unicode( ime ))
1257 ret = candlist->dwSize;
1258 if ( lpCandList && dwBufLen >= ret )
1259 memcpy(lpCandList, candlist, ret);
1261 else
1262 ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
1264 done:
1265 ImmUnlockIMCC(data->IMC.hCandInfo);
1266 return ret;
1269 /***********************************************************************
1270 * ImmGetCandidateListCountA (IMM32.@)
1272 DWORD WINAPI ImmGetCandidateListCountA(
1273 HIMC hIMC, LPDWORD lpdwListCount)
1275 struct imc *data = get_imc_data( hIMC );
1276 LPCANDIDATEINFO candinfo;
1277 DWORD ret, count;
1278 struct ime *ime;
1280 TRACE("%p, %p\n", hIMC, lpdwListCount);
1282 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1283 return 0;
1285 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1287 *lpdwListCount = count = candinfo->dwCount;
1289 if (!(ime = imc_select_ime( data )))
1290 ret = 0;
1291 else if (!ime_is_unicode( ime ))
1292 ret = candinfo->dwSize;
1293 else
1295 ret = sizeof(CANDIDATEINFO);
1296 while ( count-- )
1297 ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
1300 ImmUnlockIMCC(data->IMC.hCandInfo);
1301 return ret;
1304 /***********************************************************************
1305 * ImmGetCandidateListCountW (IMM32.@)
1307 DWORD WINAPI ImmGetCandidateListCountW(
1308 HIMC hIMC, LPDWORD lpdwListCount)
1310 struct imc *data = get_imc_data( hIMC );
1311 LPCANDIDATEINFO candinfo;
1312 DWORD ret, count;
1313 struct ime *ime;
1315 TRACE("%p, %p\n", hIMC, lpdwListCount);
1317 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1318 return 0;
1320 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1322 *lpdwListCount = count = candinfo->dwCount;
1324 if (!(ime = imc_select_ime( data )))
1325 ret = 0;
1326 else if (ime_is_unicode( ime ))
1327 ret = candinfo->dwSize;
1328 else
1330 ret = sizeof(CANDIDATEINFO);
1331 while ( count-- )
1332 ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
1335 ImmUnlockIMCC(data->IMC.hCandInfo);
1336 return ret;
1339 /***********************************************************************
1340 * ImmGetCandidateListW (IMM32.@)
1342 DWORD WINAPI ImmGetCandidateListW(
1343 HIMC hIMC, DWORD dwIndex,
1344 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1346 struct imc *data = get_imc_data( hIMC );
1347 LPCANDIDATEINFO candinfo;
1348 LPCANDIDATELIST candlist;
1349 struct ime *ime;
1350 DWORD ret = 0;
1352 TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
1354 if (!data || !data->IMC.hCandInfo)
1355 return 0;
1357 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1358 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1359 goto done;
1361 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1362 if ( !candlist->dwSize || !candlist->dwCount )
1363 goto done;
1365 if (!(ime = imc_select_ime( data )))
1366 ret = 0;
1367 else if (ime_is_unicode( ime ))
1369 ret = candlist->dwSize;
1370 if ( lpCandList && dwBufLen >= ret )
1371 memcpy(lpCandList, candlist, ret);
1373 else
1374 ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
1376 done:
1377 ImmUnlockIMCC(data->IMC.hCandInfo);
1378 return ret;
1381 /***********************************************************************
1382 * ImmGetCandidateWindow (IMM32.@)
1384 BOOL WINAPI ImmGetCandidateWindow( HIMC himc, DWORD index, CANDIDATEFORM *candidate )
1386 INPUTCONTEXT *ctx;
1387 BOOL ret = TRUE;
1389 TRACE( "himc %p, index %lu, candidate %p\n", himc, index, candidate );
1391 if (!candidate) return FALSE;
1393 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
1394 if (ctx->cfCandForm[index].dwIndex == -1) ret = FALSE;
1395 else *candidate = ctx->cfCandForm[index];
1396 ImmUnlockIMC( himc );
1398 return ret;
1401 /***********************************************************************
1402 * ImmGetCompositionFontA (IMM32.@)
1404 BOOL WINAPI ImmGetCompositionFontA( HIMC himc, LOGFONTA *fontA )
1406 INPUTCONTEXT *ctx;
1407 LOGFONTW fontW;
1408 BOOL ret = TRUE;
1410 TRACE( "himc %p, fontA %p\n", himc, fontA );
1412 if (!fontA) return FALSE;
1414 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
1415 if (!(ctx->fdwInit & INIT_LOGFONT)) ret = FALSE;
1416 else if (!input_context_is_unicode( ctx )) *fontA = ctx->lfFont.A;
1417 else if ((ret = ImmGetCompositionFontW( himc, &fontW )))
1419 memcpy( fontA, &fontW, offsetof(LOGFONTA, lfFaceName) );
1420 WideCharToMultiByte( CP_ACP, 0, fontW.lfFaceName, -1, fontA->lfFaceName, LF_FACESIZE, NULL, NULL );
1422 ImmUnlockIMC( himc );
1424 return ret;
1427 /***********************************************************************
1428 * ImmGetCompositionFontW (IMM32.@)
1430 BOOL WINAPI ImmGetCompositionFontW( HIMC himc, LOGFONTW *fontW )
1432 INPUTCONTEXT *ctx;
1433 LOGFONTA fontA;
1434 BOOL ret = TRUE;
1436 TRACE( "himc %p, fontW %p\n", himc, fontW );
1438 if (!fontW) return FALSE;
1440 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
1441 if (!(ctx->fdwInit & INIT_LOGFONT)) ret = FALSE;
1442 else if (input_context_is_unicode( ctx )) *fontW = ctx->lfFont.W;
1443 else if ((ret = ImmGetCompositionFontA( himc, &fontA )))
1445 memcpy( fontW, &fontA, offsetof(LOGFONTW, lfFaceName) );
1446 MultiByteToWideChar( CP_ACP, 0, fontA.lfFaceName, -1, fontW->lfFaceName, LF_FACESIZE );
1448 ImmUnlockIMC( himc );
1450 return ret;
1454 /* Helpers for the GetCompositionString functions */
1456 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1457 length is always in bytes. */
1458 static INT CopyCompStringIMEtoClient( BOOL src_unicode, const void *src, INT src_len,
1459 void *dst, INT dst_len, BOOL dst_unicode )
1461 int char_size = dst_unicode ? sizeof(WCHAR) : sizeof(char);
1462 INT ret;
1464 if (src_unicode ^ dst_unicode)
1466 if (dst_unicode)
1467 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
1468 else
1469 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
1470 ret *= char_size;
1472 else
1474 if (dst_len)
1476 ret = min(src_len * char_size, dst_len);
1477 memcpy(dst, src, ret);
1479 else
1480 ret = src_len * char_size;
1483 return ret;
1486 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1487 passed mode. String length is in characters, attributes are in byte arrays. */
1488 static INT CopyCompAttrIMEtoClient( BOOL src_unicode, const BYTE *src, INT src_len, const void *comp_string, INT str_len,
1489 BYTE *dst, INT dst_len, BOOL unicode )
1491 union
1493 const void *str;
1494 const WCHAR *strW;
1495 const char *strA;
1496 } string;
1497 INT rc;
1499 string.str = comp_string;
1501 if (src_unicode && !unicode)
1503 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
1504 if (dst_len)
1506 int i, j = 0, k = 0;
1508 if (rc < dst_len)
1509 dst_len = rc;
1510 for (i = 0; i < str_len; ++i)
1512 int len;
1514 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
1515 for (; len > 0; --len)
1517 dst[j++] = src[k];
1519 if (j >= dst_len)
1520 goto end;
1522 ++k;
1524 end:
1525 rc = j;
1528 else if (!src_unicode && unicode)
1530 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
1531 if (dst_len)
1533 int i, j = 0;
1535 if (rc < dst_len)
1536 dst_len = rc;
1537 for (i = 0; i < str_len; ++i)
1539 if (IsDBCSLeadByte(string.strA[i]))
1540 continue;
1542 dst[j++] = src[i];
1544 if (j >= dst_len)
1545 break;
1547 rc = j;
1550 else
1552 memcpy(dst, src, min(src_len, dst_len));
1553 rc = src_len;
1556 return rc;
1559 static INT CopyCompClauseIMEtoClient( BOOL src_unicode, LPBYTE source, INT slen, LPBYTE ssource,
1560 LPBYTE target, INT tlen, BOOL unicode )
1562 INT rc;
1564 if (src_unicode && !unicode)
1566 if (tlen)
1568 int i;
1570 if (slen < tlen)
1571 tlen = slen;
1572 tlen /= sizeof (DWORD);
1573 for (i = 0; i < tlen; ++i)
1575 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1576 ((DWORD *)source)[i],
1577 NULL, 0,
1578 NULL, NULL);
1580 rc = sizeof (DWORD) * i;
1582 else
1583 rc = slen;
1585 else if (!src_unicode && unicode)
1587 if (tlen)
1589 int i;
1591 if (slen < tlen)
1592 tlen = slen;
1593 tlen /= sizeof (DWORD);
1594 for (i = 0; i < tlen; ++i)
1596 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1597 ((DWORD *)source)[i],
1598 NULL, 0);
1600 rc = sizeof (DWORD) * i;
1602 else
1603 rc = slen;
1605 else
1607 memcpy( target, source, min(slen,tlen));
1608 rc = slen;
1611 return rc;
1614 static INT CopyCompOffsetIMEtoClient( BOOL src_unicode, DWORD offset, LPBYTE ssource, BOOL unicode )
1616 int rc;
1618 if (src_unicode && !unicode)
1620 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1622 else if (!src_unicode && unicode)
1624 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1626 else
1627 rc = offset;
1629 return rc;
1632 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1633 DWORD dwBufLen, BOOL unicode)
1635 LONG rc = 0;
1636 struct imc *data = get_imc_data( hIMC );
1637 LPCOMPOSITIONSTRING compstr;
1638 BOOL src_unicode;
1639 struct ime *ime;
1640 LPBYTE compdata;
1642 TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1644 if (!data)
1645 return FALSE;
1647 if (!data->IMC.hCompStr)
1648 return FALSE;
1650 if (!(ime = imc_select_ime( data )))
1651 return FALSE;
1652 src_unicode = ime_is_unicode( ime );
1654 compdata = ImmLockIMCC(data->IMC.hCompStr);
1655 compstr = (LPCOMPOSITIONSTRING)compdata;
1657 switch (dwIndex)
1659 case GCS_RESULTSTR:
1660 TRACE("GCS_RESULTSTR\n");
1661 rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1662 break;
1663 case GCS_COMPSTR:
1664 TRACE("GCS_COMPSTR\n");
1665 rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1666 break;
1667 case GCS_COMPATTR:
1668 TRACE("GCS_COMPATTR\n");
1669 rc = CopyCompAttrIMEtoClient(src_unicode, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1670 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1671 lpBuf, dwBufLen, unicode);
1672 break;
1673 case GCS_COMPCLAUSE:
1674 TRACE("GCS_COMPCLAUSE\n");
1675 rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1676 compdata + compstr->dwCompStrOffset,
1677 lpBuf, dwBufLen, unicode);
1678 break;
1679 case GCS_RESULTCLAUSE:
1680 TRACE("GCS_RESULTCLAUSE\n");
1681 rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1682 compdata + compstr->dwResultStrOffset,
1683 lpBuf, dwBufLen, unicode);
1684 break;
1685 case GCS_RESULTREADSTR:
1686 TRACE("GCS_RESULTREADSTR\n");
1687 rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1688 break;
1689 case GCS_RESULTREADCLAUSE:
1690 TRACE("GCS_RESULTREADCLAUSE\n");
1691 rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1692 compdata + compstr->dwResultStrOffset,
1693 lpBuf, dwBufLen, unicode);
1694 break;
1695 case GCS_COMPREADSTR:
1696 TRACE("GCS_COMPREADSTR\n");
1697 rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1698 break;
1699 case GCS_COMPREADATTR:
1700 TRACE("GCS_COMPREADATTR\n");
1701 rc = CopyCompAttrIMEtoClient(src_unicode, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1702 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1703 lpBuf, dwBufLen, unicode);
1704 break;
1705 case GCS_COMPREADCLAUSE:
1706 TRACE("GCS_COMPREADCLAUSE\n");
1707 rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1708 compdata + compstr->dwCompStrOffset,
1709 lpBuf, dwBufLen, unicode);
1710 break;
1711 case GCS_CURSORPOS:
1712 TRACE("GCS_CURSORPOS\n");
1713 rc = CopyCompOffsetIMEtoClient(src_unicode, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1714 break;
1715 case GCS_DELTASTART:
1716 TRACE("GCS_DELTASTART\n");
1717 rc = CopyCompOffsetIMEtoClient(src_unicode, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1718 break;
1719 default:
1720 FIXME("Unhandled index 0x%lx\n",dwIndex);
1721 break;
1724 ImmUnlockIMCC(data->IMC.hCompStr);
1726 return rc;
1729 /***********************************************************************
1730 * ImmGetCompositionStringA (IMM32.@)
1732 LONG WINAPI ImmGetCompositionStringA(
1733 HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1735 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1739 /***********************************************************************
1740 * ImmGetCompositionStringW (IMM32.@)
1742 LONG WINAPI ImmGetCompositionStringW(
1743 HIMC hIMC, DWORD dwIndex,
1744 LPVOID lpBuf, DWORD dwBufLen)
1746 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1749 /***********************************************************************
1750 * ImmGetCompositionWindow (IMM32.@)
1752 BOOL WINAPI ImmGetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition )
1754 INPUTCONTEXT *ctx;
1755 BOOL ret;
1757 TRACE( "himc %p, composition %p\n", himc, composition );
1759 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
1760 if ((ret = !!(ctx->fdwInit & INIT_COMPFORM))) *composition = ctx->cfCompForm;
1761 ImmUnlockIMC( himc );
1763 return ret;
1766 /***********************************************************************
1767 * ImmGetContext (IMM32.@)
1770 HIMC WINAPI ImmGetContext( HWND hwnd )
1772 TRACE( "hwnd %p\n", hwnd );
1773 return NtUserGetWindowInputContext( hwnd );
1776 /***********************************************************************
1777 * ImmGetConversionListA (IMM32.@)
1779 DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDIDATELIST *listA,
1780 DWORD lengthA, UINT flags )
1782 struct ime *ime;
1783 DWORD ret;
1785 TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl, himc,
1786 debugstr_a(srcA), listA, lengthA, flags );
1788 if (!(ime = ime_acquire( hkl ))) return 0;
1790 if (!ime_is_unicode( ime ))
1791 ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags );
1792 else
1794 CANDIDATELIST *listW;
1795 WCHAR *srcW = strdupAtoW( srcA );
1796 DWORD lengthW = ime->pImeConversionList( himc, srcW, NULL, 0, flags );
1798 if (!(listW = malloc( lengthW ))) ret = 0;
1799 else
1801 ime->pImeConversionList( himc, srcW, listW, lengthW, flags );
1802 ret = convert_candidatelist_WtoA( listW, listA, lengthA );
1803 free( listW );
1805 free( srcW );
1808 ime_release( ime );
1809 return ret;
1812 /***********************************************************************
1813 * ImmGetConversionListW (IMM32.@)
1815 DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDIDATELIST *listW,
1816 DWORD lengthW, UINT flags )
1818 struct ime *ime;
1819 DWORD ret;
1821 TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl, himc,
1822 debugstr_w(srcW), listW, lengthW, flags );
1824 if (!(ime = ime_acquire( hkl ))) return 0;
1826 if (ime_is_unicode( ime ))
1827 ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags );
1828 else
1830 CANDIDATELIST *listA;
1831 char *srcA = strdupWtoA( srcW );
1832 DWORD lengthA = ime->pImeConversionList( himc, srcA, NULL, 0, flags );
1834 if (!(listA = malloc( lengthA ))) ret = 0;
1835 else
1837 ime->pImeConversionList( himc, srcA, listA, lengthA, flags );
1838 ret = convert_candidatelist_AtoW( listA, listW, lengthW );
1839 free( listA );
1841 free( srcA );
1844 ime_release( ime );
1845 return ret;
1848 /***********************************************************************
1849 * ImmGetConversionStatus (IMM32.@)
1851 BOOL WINAPI ImmGetConversionStatus( HIMC himc, DWORD *conversion, DWORD *sentence )
1853 INPUTCONTEXT *ctx;
1855 TRACE( "himc %p, conversion %p, sentence %p\n", himc, conversion, sentence );
1857 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
1858 if (conversion) *conversion = ctx->fdwConversion;
1859 if (sentence) *sentence = ctx->fdwSentence;
1860 ImmUnlockIMC( himc );
1862 return TRUE;
1865 /***********************************************************************
1866 * ImmGetDefaultIMEWnd (IMM32.@)
1868 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1870 return NtUserGetDefaultImeWindow(hWnd);
1873 /***********************************************************************
1874 * ImmGetDescriptionA (IMM32.@)
1876 UINT WINAPI ImmGetDescriptionA( HKL hkl, LPSTR bufferA, UINT lengthA )
1878 WCHAR *bufferW;
1879 DWORD lengthW;
1881 TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl, bufferA, lengthA );
1883 if (!(lengthW = ImmGetDescriptionW( hkl, NULL, 0 ))) return 0;
1884 if (!(bufferW = malloc( (lengthW + 1) * sizeof(WCHAR) ))) return 0;
1885 lengthW = ImmGetDescriptionW( hkl, bufferW, lengthW + 1 );
1886 lengthA = WideCharToMultiByte( CP_ACP, 0, bufferW, lengthW, bufferA,
1887 bufferA ? lengthA : 0, NULL, NULL );
1888 if (bufferA) bufferA[lengthA] = 0;
1889 free( bufferW );
1891 return lengthA;
1894 /***********************************************************************
1895 * ImmGetDescriptionW (IMM32.@)
1897 UINT WINAPI ImmGetDescriptionW( HKL hkl, WCHAR *buffer, UINT length )
1899 WCHAR path[MAX_PATH];
1900 HKEY hkey = 0;
1901 DWORD size;
1903 TRACE( "hkl %p, buffer %p, length %u\n", hkl, buffer, length );
1905 swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl );
1906 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &hkey )) return 0;
1908 size = ARRAY_SIZE(path) * sizeof(WCHAR);
1909 if (RegGetValueW( hkey, NULL, L"Layout Text", RRF_RT_REG_SZ, NULL, path, &size )) *path = 0;
1910 RegCloseKey( hkey );
1912 size = wcslen( path );
1913 if (!buffer) return size;
1915 lstrcpynW( buffer, path, length );
1916 return wcslen( buffer );
1919 /***********************************************************************
1920 * ImmGetGuideLineA (IMM32.@)
1922 DWORD WINAPI ImmGetGuideLineA(
1923 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1925 FIXME("(%p, %ld, %s, %ld): stub\n",
1926 hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1928 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1929 return 0;
1932 /***********************************************************************
1933 * ImmGetGuideLineW (IMM32.@)
1935 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1937 FIXME("(%p, %ld, %s, %ld): stub\n",
1938 hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1940 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1941 return 0;
1944 /***********************************************************************
1945 * ImmGetIMEFileNameA (IMM32.@)
1947 UINT WINAPI ImmGetIMEFileNameA( HKL hkl, char *bufferA, UINT lengthA )
1949 WCHAR *bufferW;
1950 DWORD lengthW;
1952 TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl, bufferA, lengthA );
1954 if (!(lengthW = ImmGetIMEFileNameW( hkl, NULL, 0 ))) return 0;
1955 if (!(bufferW = malloc( (lengthW + 1) * sizeof(WCHAR) ))) return 0;
1956 lengthW = ImmGetIMEFileNameW( hkl, bufferW, lengthW + 1 );
1957 lengthA = WideCharToMultiByte( CP_ACP, 0, bufferW, lengthW, bufferA,
1958 bufferA ? lengthA : 0, NULL, NULL );
1959 if (bufferA) bufferA[lengthA] = 0;
1960 free( bufferW );
1962 return lengthA;
1965 /***********************************************************************
1966 * ImmGetIMEFileNameW (IMM32.@)
1968 UINT WINAPI ImmGetIMEFileNameW( HKL hkl, WCHAR *buffer, UINT length )
1970 WCHAR path[MAX_PATH];
1971 HKEY hkey = 0;
1972 DWORD size;
1974 TRACE( "hkl %p, buffer %p, length %u\n", hkl, buffer, length );
1976 swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl );
1977 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &hkey )) return 0;
1979 size = ARRAY_SIZE(path) * sizeof(WCHAR);
1980 if (RegGetValueW( hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, path, &size )) *path = 0;
1981 RegCloseKey( hkey );
1983 size = wcslen( path );
1984 if (!buffer) return size;
1986 lstrcpynW( buffer, path, length );
1987 return wcslen( buffer );
1990 /***********************************************************************
1991 * ImmGetOpenStatus (IMM32.@)
1993 BOOL WINAPI ImmGetOpenStatus( HIMC himc )
1995 INPUTCONTEXT *ctx;
1996 BOOL status;
1998 TRACE( "himc %p\n", himc );
2000 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2001 status = ctx->fOpen;
2002 ImmUnlockIMC( himc );
2004 return status;
2007 /***********************************************************************
2008 * ImmGetProperty (IMM32.@)
2010 DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index )
2012 struct ime *ime;
2013 DWORD ret;
2015 TRACE( "hkl %p, index %lu.\n", hkl, index );
2017 if (!(ime = ime_acquire( hkl ))) return 0;
2019 switch (index)
2021 case IGP_PROPERTY: ret = ime->info.fdwProperty; break;
2022 case IGP_CONVERSION: ret = ime->info.fdwConversionCaps; break;
2023 case IGP_SENTENCE: ret = ime->info.fdwSentenceCaps; break;
2024 case IGP_SETCOMPSTR: ret = ime->info.fdwSCSCaps; break;
2025 case IGP_SELECT: ret = ime->info.fdwSelectCaps; break;
2026 case IGP_GETIMEVERSION: ret = IMEVER_0400; break;
2027 case IGP_UI: ret = 0; break;
2028 default: ret = 0; break;
2031 ime_release( ime );
2032 return ret;
2035 /***********************************************************************
2036 * ImmGetRegisterWordStyleA (IMM32.@)
2038 UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA )
2040 struct ime *ime;
2041 UINT ret;
2043 TRACE( "hkl %p, count %u, styleA %p.\n", hkl, count, styleA );
2045 if (!(ime = ime_acquire( hkl ))) return 0;
2047 if (!ime_is_unicode( ime ))
2048 ret = ime->pImeGetRegisterWordStyle( count, styleA );
2049 else
2051 STYLEBUFW styleW;
2052 ret = ime->pImeGetRegisterWordStyle( count, &styleW );
2053 WideCharToMultiByte( CP_ACP, 0, styleW.szDescription, -1, styleA->szDescription, 32, NULL, NULL );
2054 styleA->dwStyle = styleW.dwStyle;
2057 ime_release( ime );
2058 return ret;
2061 /***********************************************************************
2062 * ImmGetRegisterWordStyleW (IMM32.@)
2064 UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW )
2066 struct ime *ime;
2067 UINT ret;
2069 TRACE( "hkl %p, count %u, styleW %p.\n", hkl, count, styleW );
2071 if (!(ime = ime_acquire( hkl ))) return 0;
2073 if (ime_is_unicode( ime ))
2074 ret = ime->pImeGetRegisterWordStyle( count, styleW );
2075 else
2077 STYLEBUFA styleA;
2078 ret = ime->pImeGetRegisterWordStyle( count, &styleA );
2079 MultiByteToWideChar( CP_ACP, 0, styleA.szDescription, -1, styleW->szDescription, 32 );
2080 styleW->dwStyle = styleA.dwStyle;
2083 ime_release( ime );
2084 return ret;
2087 /***********************************************************************
2088 * ImmGetStatusWindowPos (IMM32.@)
2090 BOOL WINAPI ImmGetStatusWindowPos( HIMC himc, POINT *pos )
2092 INPUTCONTEXT *ctx;
2093 BOOL ret;
2095 TRACE( "himc %p, pos %p\n", himc, pos );
2097 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2098 if ((ret = !!(ctx->fdwInit & INIT_STATUSWNDPOS))) *pos = ctx->ptStatusWndPos;
2099 ImmUnlockIMC( himc );
2101 return ret;
2104 /***********************************************************************
2105 * ImmGetVirtualKey (IMM32.@)
2107 UINT WINAPI ImmGetVirtualKey( HWND hwnd )
2109 HIMC himc = ImmGetContext( hwnd );
2110 struct imc *imc;
2112 TRACE( "%p\n", hwnd );
2114 if ((imc = get_imc_data( himc ))) return imc->vkey;
2115 return VK_PROCESSKEY;
2118 /***********************************************************************
2119 * ImmInstallIMEA (IMM32.@)
2121 HKL WINAPI ImmInstallIMEA( const char *filenameA, const char *descriptionA )
2123 WCHAR *filenameW = strdupAtoW( filenameA ), *descriptionW = strdupAtoW( descriptionA );
2124 HKL hkl;
2126 TRACE( "filenameA %s, descriptionA %s\n", debugstr_a(filenameA), debugstr_a(descriptionA) );
2128 hkl = ImmInstallIMEW( filenameW, descriptionW );
2129 free( descriptionW );
2130 free( filenameW );
2132 return hkl;
2135 static LCID get_ime_file_lang( const WCHAR *filename )
2137 DWORD *languages;
2138 LCID lcid = 0;
2139 void *info;
2140 UINT len;
2142 if (!(len = GetFileVersionInfoSizeW( filename, NULL ))) return 0;
2143 if (!(info = malloc( len ))) goto done;
2144 if (!GetFileVersionInfoW( filename, 0, len, info )) goto done;
2145 if (!VerQueryValueW( info, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done;
2146 lcid = languages[0];
2148 done:
2149 free( info );
2150 return lcid;
2153 /***********************************************************************
2154 * ImmInstallIMEW (IMM32.@)
2156 HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description )
2158 WCHAR path[ARRAY_SIZE(layouts_formatW)+8], buffer[MAX_PATH];
2159 LCID lcid;
2160 WORD count = 0x20;
2161 const WCHAR *tmp;
2162 DWORD length;
2163 HKEY hkey;
2164 HKL hkl;
2166 TRACE( "filename %s, description %s\n", debugstr_w(filename), debugstr_w(description) );
2168 if (!filename || !description || !(lcid = get_ime_file_lang( filename )))
2170 SetLastError( ERROR_INVALID_PARAMETER );
2171 return 0;
2174 while (count < 0xfff)
2176 DWORD disposition = 0;
2178 hkl = (HKL)(UINT_PTR)MAKELONG( lcid, 0xe000 | count );
2179 swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl);
2180 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, path, 0, NULL, 0,
2181 KEY_WRITE, NULL, &hkey, &disposition ))
2183 if (disposition == REG_CREATED_NEW_KEY) break;
2184 RegCloseKey( hkey );
2187 count++;
2190 if (count == 0xfff)
2192 WARN("Unable to find slot to install IME\n");
2193 return 0;
2196 if ((tmp = wcsrchr( filename, '\\' ))) tmp++;
2197 else tmp = filename;
2199 length = LCMapStringW( LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, tmp, -1, buffer, ARRAY_SIZE(buffer) );
2201 if (RegSetValueExW( hkey, L"Ime File", 0, REG_SZ, (const BYTE *)buffer, length * sizeof(WCHAR) ) ||
2202 RegSetValueExW( hkey, L"Layout Text", 0, REG_SZ, (const BYTE *)description,
2203 (wcslen(description) + 1) * sizeof(WCHAR) ))
2205 WARN( "Unable to write registry to install IME\n");
2206 hkl = 0;
2208 RegCloseKey( hkey );
2210 if (!hkl) RegDeleteKeyW( HKEY_LOCAL_MACHINE, path );
2211 return hkl;
2214 /***********************************************************************
2215 * ImmIsIME (IMM32.@)
2217 BOOL WINAPI ImmIsIME( HKL hkl )
2219 TRACE( "hkl %p\n", hkl );
2220 if (!hkl) return FALSE;
2221 return TRUE;
2224 /***********************************************************************
2225 * ImmIsUIMessageA (IMM32.@)
2227 BOOL WINAPI ImmIsUIMessageA(
2228 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2230 TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
2231 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2232 (msg == WM_IME_SETCONTEXT) ||
2233 (msg == WM_IME_NOTIFY) ||
2234 (msg == WM_IME_COMPOSITIONFULL) ||
2235 (msg == WM_IME_SELECT) ||
2236 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2238 if (hWndIME)
2239 SendMessageA(hWndIME, msg, wParam, lParam);
2241 return TRUE;
2243 return FALSE;
2246 /***********************************************************************
2247 * ImmIsUIMessageW (IMM32.@)
2249 BOOL WINAPI ImmIsUIMessageW(
2250 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2252 TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
2253 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2254 (msg == WM_IME_SETCONTEXT) ||
2255 (msg == WM_IME_NOTIFY) ||
2256 (msg == WM_IME_COMPOSITIONFULL) ||
2257 (msg == WM_IME_SELECT) ||
2258 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2260 if (hWndIME)
2261 SendMessageW(hWndIME, msg, wParam, lParam);
2263 return TRUE;
2265 return FALSE;
2268 /***********************************************************************
2269 * ImmNotifyIME (IMM32.@)
2271 BOOL WINAPI ImmNotifyIME(
2272 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2274 struct imc *data = get_imc_data( hIMC );
2275 struct ime *ime;
2277 TRACE("(%p, %ld, %ld, %ld)\n",
2278 hIMC, dwAction, dwIndex, dwValue);
2280 if (hIMC == NULL)
2282 SetLastError(ERROR_SUCCESS);
2283 return FALSE;
2286 if (!data)
2288 return FALSE;
2291 if (!(ime = imc_select_ime( data ))) return FALSE;
2292 return ime->pNotifyIME( hIMC, dwAction, dwIndex, dwValue );
2295 /***********************************************************************
2296 * ImmRegisterWordA (IMM32.@)
2298 BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA )
2300 struct ime *ime;
2301 BOOL ret;
2303 TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) );
2305 if (!(ime = ime_acquire( hkl ))) return FALSE;
2307 if (!ime_is_unicode( ime ))
2308 ret = ime->pImeRegisterWord( readingA, style, stringA );
2309 else
2311 WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
2312 ret = ime->pImeRegisterWord( readingW, style, stringW );
2313 free( readingW );
2314 free( stringW );
2317 ime_release( ime );
2318 return ret;
2321 /***********************************************************************
2322 * ImmRegisterWordW (IMM32.@)
2324 BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW )
2326 struct ime *ime;
2327 BOOL ret;
2329 TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) );
2331 if (!(ime = ime_acquire( hkl ))) return FALSE;
2333 if (ime_is_unicode( ime ))
2334 ret = ime->pImeRegisterWord( readingW, style, stringW );
2335 else
2337 char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
2338 ret = ime->pImeRegisterWord( readingA, style, stringA );
2339 free( readingA );
2340 free( stringA );
2343 ime_release( ime );
2344 return ret;
2347 /***********************************************************************
2348 * ImmReleaseContext (IMM32.@)
2350 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2352 static BOOL shown = FALSE;
2354 if (!shown) {
2355 FIXME("(%p, %p): stub\n", hWnd, hIMC);
2356 shown = TRUE;
2358 return TRUE;
2361 /***********************************************************************
2362 * ImmRequestMessageA(IMM32.@)
2364 LRESULT WINAPI ImmRequestMessageA( HIMC himc, WPARAM wparam, LPARAM lparam )
2366 INPUTCONTEXT *ctx;
2367 LRESULT res;
2369 TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam );
2371 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2373 switch (wparam)
2375 case IMR_CANDIDATEWINDOW:
2376 case IMR_COMPOSITIONFONT:
2377 case IMR_COMPOSITIONWINDOW:
2378 case IMR_CONFIRMRECONVERTSTRING:
2379 case IMR_DOCUMENTFEED:
2380 case IMR_QUERYCHARPOSITION:
2381 case IMR_RECONVERTSTRING:
2382 break;
2383 default:
2384 return FALSE;
2387 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2388 res = SendMessageA( ctx->hWnd, WM_IME_REQUEST, wparam, lparam );
2389 ImmUnlockIMC( himc );
2391 return res;
2394 /***********************************************************************
2395 * ImmRequestMessageW(IMM32.@)
2397 LRESULT WINAPI ImmRequestMessageW( HIMC himc, WPARAM wparam, LPARAM lparam )
2399 INPUTCONTEXT *ctx;
2400 LRESULT res;
2402 TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam );
2404 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2406 switch (wparam)
2408 case IMR_CANDIDATEWINDOW:
2409 case IMR_COMPOSITIONFONT:
2410 case IMR_COMPOSITIONWINDOW:
2411 case IMR_CONFIRMRECONVERTSTRING:
2412 case IMR_DOCUMENTFEED:
2413 case IMR_QUERYCHARPOSITION:
2414 case IMR_RECONVERTSTRING:
2415 break;
2416 default:
2417 return FALSE;
2420 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2421 res = SendMessageW( ctx->hWnd, WM_IME_REQUEST, wparam, lparam );
2422 ImmUnlockIMC( himc );
2424 return res;
2427 /***********************************************************************
2428 * ImmSetCandidateWindow (IMM32.@)
2430 BOOL WINAPI ImmSetCandidateWindow( HIMC himc, CANDIDATEFORM *candidate )
2432 INPUTCONTEXT *ctx;
2434 TRACE( "hwnd %p, candidate %s\n", himc, debugstr_candidate( candidate ) );
2436 if (!candidate) return FALSE;
2437 if (candidate->dwIndex >= ARRAY_SIZE(ctx->cfCandForm)) return FALSE;
2439 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2440 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2442 ctx->cfCandForm[candidate->dwIndex] = *candidate;
2444 ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS );
2445 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCANDIDATEPOS, 1 << candidate->dwIndex );
2447 ImmUnlockIMC( himc );
2449 return TRUE;
2452 /***********************************************************************
2453 * ImmSetCompositionFontA (IMM32.@)
2455 BOOL WINAPI ImmSetCompositionFontA( HIMC himc, LOGFONTA *fontA )
2457 INPUTCONTEXT *ctx;
2458 BOOL ret = TRUE;
2460 TRACE( "hwnd %p, fontA %p\n", himc, fontA );
2462 if (!fontA) return FALSE;
2464 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2465 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2467 if (input_context_is_unicode( ctx ))
2469 LOGFONTW fontW;
2470 memcpy( &fontW, fontA, offsetof(LOGFONTW, lfFaceName) );
2471 MultiByteToWideChar( CP_ACP, 0, fontA->lfFaceName, -1, fontW.lfFaceName, LF_FACESIZE );
2472 ret = ImmSetCompositionFontW( himc, &fontW );
2474 else
2476 ctx->lfFont.A = *fontA;
2477 ctx->fdwInit |= INIT_LOGFONT;
2479 ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT );
2480 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0 );
2483 ImmUnlockIMC( himc );
2485 return ret;
2488 /***********************************************************************
2489 * ImmSetCompositionFontW (IMM32.@)
2491 BOOL WINAPI ImmSetCompositionFontW( HIMC himc, LOGFONTW *fontW )
2493 INPUTCONTEXT *ctx;
2494 BOOL ret = TRUE;
2496 TRACE( "hwnd %p, fontW %p\n", himc, fontW );
2498 if (!fontW) return FALSE;
2500 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2501 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2503 if (!input_context_is_unicode( ctx ))
2505 LOGFONTA fontA;
2506 memcpy( &fontA, fontW, offsetof(LOGFONTA, lfFaceName) );
2507 WideCharToMultiByte( CP_ACP, 0, fontW->lfFaceName, -1, fontA.lfFaceName, LF_FACESIZE, NULL, NULL );
2508 ret = ImmSetCompositionFontA( himc, &fontA );
2510 else
2512 ctx->lfFont.W = *fontW;
2513 ctx->fdwInit |= INIT_LOGFONT;
2515 ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT );
2516 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0 );
2519 ImmUnlockIMC( himc );
2521 return ret;
2524 /***********************************************************************
2525 * ImmSetCompositionStringA (IMM32.@)
2527 BOOL WINAPI ImmSetCompositionStringA(
2528 HIMC hIMC, DWORD dwIndex,
2529 LPCVOID lpComp, DWORD dwCompLen,
2530 LPCVOID lpRead, DWORD dwReadLen)
2532 DWORD comp_len;
2533 DWORD read_len;
2534 WCHAR *CompBuffer = NULL;
2535 WCHAR *ReadBuffer = NULL;
2536 BOOL rc;
2537 struct imc *data = get_imc_data( hIMC );
2538 struct ime *ime;
2540 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2541 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2543 if (!data)
2544 return FALSE;
2546 if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2548 if (!(dwIndex == SCS_SETSTR ||
2549 dwIndex == SCS_CHANGEATTR ||
2550 dwIndex == SCS_CHANGECLAUSE ||
2551 dwIndex == SCS_SETRECONVERTSTRING ||
2552 dwIndex == SCS_QUERYRECONVERTSTRING))
2553 return FALSE;
2555 if (!(ime = imc_select_ime( data ))) return FALSE;
2556 if (!ime_is_unicode( ime )) return ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen );
2558 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2559 if (comp_len)
2561 CompBuffer = malloc( comp_len * sizeof(WCHAR) );
2562 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2565 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2566 if (read_len)
2568 ReadBuffer = malloc( read_len * sizeof(WCHAR) );
2569 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2572 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2573 ReadBuffer, read_len);
2575 free( CompBuffer );
2576 free( ReadBuffer );
2578 return rc;
2581 /***********************************************************************
2582 * ImmSetCompositionStringW (IMM32.@)
2584 BOOL WINAPI ImmSetCompositionStringW(
2585 HIMC hIMC, DWORD dwIndex,
2586 LPCVOID lpComp, DWORD dwCompLen,
2587 LPCVOID lpRead, DWORD dwReadLen)
2589 DWORD comp_len;
2590 DWORD read_len;
2591 CHAR *CompBuffer = NULL;
2592 CHAR *ReadBuffer = NULL;
2593 BOOL rc;
2594 struct imc *data = get_imc_data( hIMC );
2595 struct ime *ime;
2597 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2598 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2600 if (!data)
2601 return FALSE;
2603 if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2605 if (!(dwIndex == SCS_SETSTR ||
2606 dwIndex == SCS_CHANGEATTR ||
2607 dwIndex == SCS_CHANGECLAUSE ||
2608 dwIndex == SCS_SETRECONVERTSTRING ||
2609 dwIndex == SCS_QUERYRECONVERTSTRING))
2610 return FALSE;
2612 if (!(ime = imc_select_ime( data ))) return FALSE;
2613 if (ime_is_unicode( ime )) return ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen );
2615 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2616 NULL);
2617 if (comp_len)
2619 CompBuffer = malloc( comp_len );
2620 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2621 NULL, NULL);
2624 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2625 NULL);
2626 if (read_len)
2628 ReadBuffer = malloc( read_len );
2629 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2630 NULL, NULL);
2633 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2634 ReadBuffer, read_len);
2636 free( CompBuffer );
2637 free( ReadBuffer );
2639 return rc;
2642 /***********************************************************************
2643 * ImmSetCompositionWindow (IMM32.@)
2645 BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition )
2647 INPUTCONTEXT *ctx;
2649 TRACE( "himc %p, composition %s\n", himc, debugstr_composition( composition ) );
2651 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2652 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2654 ctx->cfCompForm = *composition;
2655 ctx->fdwInit |= INIT_COMPFORM;
2657 ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONWINDOW );
2658 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0 );
2660 ImmUnlockIMC( himc );
2662 return TRUE;
2665 /***********************************************************************
2666 * ImmSetConversionStatus (IMM32.@)
2668 BOOL WINAPI ImmSetConversionStatus( HIMC himc, DWORD conversion, DWORD sentence )
2670 DWORD old_conversion, old_sentence;
2671 INPUTCONTEXT *ctx;
2673 TRACE( "himc %p, conversion %#lx, sentence %#lx\n", himc, conversion, sentence );
2675 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2676 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2678 if (conversion != ctx->fdwConversion)
2680 old_conversion = ctx->fdwConversion;
2681 ctx->fdwConversion = conversion;
2682 ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_conversion, IMC_SETCONVERSIONMODE );
2683 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0 );
2686 if (sentence != ctx->fdwSentence)
2688 old_sentence = ctx->fdwSentence;
2689 ctx->fdwSentence = sentence;
2690 ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_sentence, IMC_SETSENTENCEMODE );
2691 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0 );
2694 ImmUnlockIMC( himc );
2696 return TRUE;
2699 /***********************************************************************
2700 * ImmSetOpenStatus (IMM32.@)
2702 BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status )
2704 INPUTCONTEXT *ctx;
2706 TRACE( "himc %p, status %u\n", himc, status );
2708 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2709 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2711 if (status != ctx->fOpen)
2713 ctx->fOpen = status;
2714 ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS );
2715 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0 );
2718 ImmUnlockIMC( himc );
2720 return TRUE;
2723 /***********************************************************************
2724 * ImmSetStatusWindowPos (IMM32.@)
2726 BOOL WINAPI ImmSetStatusWindowPos( HIMC himc, POINT *pos )
2728 INPUTCONTEXT *ctx;
2730 TRACE( "himc %p, pos %s\n", himc, wine_dbgstr_point( pos ) );
2732 if (!pos)
2734 SetLastError( ERROR_INVALID_HANDLE );
2735 return FALSE;
2738 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
2739 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
2741 ctx->ptStatusWndPos = *pos;
2742 ctx->fdwInit |= INIT_STATUSWNDPOS;
2744 ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS );
2745 SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSTATUSWINDOWPOS, 0 );
2747 ImmUnlockIMC( himc );
2749 return TRUE;
2752 /***********************************************************************
2753 * ImmCreateSoftKeyboard(IMM32.@)
2755 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2757 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2758 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2759 return 0;
2762 /***********************************************************************
2763 * ImmDestroySoftKeyboard(IMM32.@)
2765 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2767 FIXME("(%p): stub\n", hSoftWnd);
2768 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2769 return FALSE;
2772 /***********************************************************************
2773 * ImmShowSoftKeyboard(IMM32.@)
2775 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2777 FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2778 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2779 return FALSE;
2782 /***********************************************************************
2783 * ImmSimulateHotKey (IMM32.@)
2785 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2787 FIXME("(%p, %ld): stub\n", hWnd, dwHotKeyID);
2788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2789 return FALSE;
2792 /***********************************************************************
2793 * ImmUnregisterWordA (IMM32.@)
2795 BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA )
2797 struct ime *ime;
2798 BOOL ret;
2800 TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) );
2802 if (!(ime = ime_acquire( hkl ))) return FALSE;
2804 if (!ime_is_unicode( ime ))
2805 ret = ime->pImeUnregisterWord( readingA, style, stringA );
2806 else
2808 WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
2809 ret = ime->pImeUnregisterWord( readingW, style, stringW );
2810 free( readingW );
2811 free( stringW );
2814 ime_release( ime );
2815 return ret;
2818 /***********************************************************************
2819 * ImmUnregisterWordW (IMM32.@)
2821 BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW )
2823 struct ime *ime;
2824 BOOL ret;
2826 TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) );
2828 if (!(ime = ime_acquire( hkl ))) return FALSE;
2830 if (ime_is_unicode( ime ))
2831 ret = ime->pImeUnregisterWord( readingW, style, stringW );
2832 else
2834 char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
2835 ret = ime->pImeUnregisterWord( readingA, style, stringA );
2836 free( readingA );
2837 free( stringA );
2840 ime_release( ime );
2841 return ret;
2844 /***********************************************************************
2845 * ImmGetImeMenuItemsA (IMM32.@)
2847 DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOA *parentA,
2848 IMEMENUITEMINFOA *menuA, DWORD size )
2850 struct imc *data = get_imc_data( himc );
2851 struct ime *ime;
2852 DWORD ret;
2854 TRACE( "himc %p, flags %#lx, type %lu, parentA %p, menuA %p, size %lu.\n",
2855 himc, flags, type, parentA, menuA, size );
2857 if (!data)
2859 SetLastError( ERROR_INVALID_HANDLE );
2860 return 0;
2863 if (!(ime = imc_select_ime( data ))) return 0;
2864 if (!ime_is_unicode( ime ) || (!parentA && !menuA))
2865 ret = ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size );
2866 else
2868 IMEMENUITEMINFOW tmpW, *menuW, *parentW = parentA ? &tmpW : NULL;
2870 if (!menuA) menuW = NULL;
2871 else
2873 int count = size / sizeof(LPIMEMENUITEMINFOA);
2874 size = count * sizeof(IMEMENUITEMINFOW);
2875 menuW = malloc( size );
2878 ret = ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size );
2880 if (parentA)
2882 memcpy( parentA, parentW, sizeof(IMEMENUITEMINFOA) );
2883 parentA->hbmpItem = parentW->hbmpItem;
2884 WideCharToMultiByte( CP_ACP, 0, parentW->szString, -1, parentA->szString,
2885 IMEMENUITEM_STRING_SIZE, NULL, NULL );
2887 if (menuA && ret)
2889 unsigned int i;
2890 for (i = 0; i < ret; i++)
2892 memcpy( &menuA[i], &menuW[1], sizeof(IMEMENUITEMINFOA) );
2893 menuA[i].hbmpItem = menuW[i].hbmpItem;
2894 WideCharToMultiByte( CP_ACP, 0, menuW[i].szString, -1, menuA[i].szString,
2895 IMEMENUITEM_STRING_SIZE, NULL, NULL );
2898 free( menuW );
2901 return ret;
2904 /***********************************************************************
2905 * ImmGetImeMenuItemsW (IMM32.@)
2907 DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parentW,
2908 IMEMENUITEMINFOW *menuW, DWORD size )
2910 struct imc *data = get_imc_data( himc );
2911 struct ime *ime;
2912 DWORD ret;
2914 TRACE( "himc %p, flags %#lx, type %lu, parentW %p, menuW %p, size %lu.\n",
2915 himc, flags, type, parentW, menuW, size );
2917 if (!data)
2919 SetLastError( ERROR_INVALID_HANDLE );
2920 return 0;
2923 if (!(ime = imc_select_ime( data ))) return 0;
2924 if (ime_is_unicode( ime ) || (!parentW && !menuW))
2925 ret = ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size );
2926 else
2928 IMEMENUITEMINFOA tmpA, *menuA, *parentA = parentW ? &tmpA : NULL;
2930 if (!menuW) menuA = NULL;
2931 else
2933 int count = size / sizeof(LPIMEMENUITEMINFOW);
2934 size = count * sizeof(IMEMENUITEMINFOA);
2935 menuA = malloc( size );
2938 ret = ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size );
2940 if (parentW)
2942 memcpy( parentW, parentA, sizeof(IMEMENUITEMINFOA) );
2943 parentW->hbmpItem = parentA->hbmpItem;
2944 MultiByteToWideChar( CP_ACP, 0, parentA->szString, -1, parentW->szString, IMEMENUITEM_STRING_SIZE );
2946 if (menuW && ret)
2948 unsigned int i;
2949 for (i = 0; i < ret; i++)
2951 memcpy( &menuW[i], &menuA[1], sizeof(IMEMENUITEMINFOA) );
2952 menuW[i].hbmpItem = menuA[i].hbmpItem;
2953 MultiByteToWideChar( CP_ACP, 0, menuA[i].szString, -1, menuW[i].szString, IMEMENUITEM_STRING_SIZE );
2956 free( menuA );
2959 return ret;
2962 /***********************************************************************
2963 * ImmLockIMC(IMM32.@)
2965 INPUTCONTEXT *WINAPI ImmLockIMC( HIMC himc )
2967 struct imc *imc = get_imc_data( himc );
2969 TRACE( "himc %p\n", himc );
2971 if (!imc) return NULL;
2972 imc->dwLock++;
2974 imc_select_ime( imc );
2975 return &imc->IMC;
2978 /***********************************************************************
2979 * ImmUnlockIMC(IMM32.@)
2981 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2983 struct imc *data = get_imc_data( hIMC );
2985 if (!data)
2986 return FALSE;
2987 if (data->dwLock)
2988 data->dwLock--;
2989 return TRUE;
2992 /***********************************************************************
2993 * ImmGetIMCLockCount(IMM32.@)
2995 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2997 struct imc *data = get_imc_data( hIMC );
2998 if (!data)
2999 return 0;
3000 return data->dwLock;
3003 /***********************************************************************
3004 * ImmCreateIMCC(IMM32.@)
3006 HIMCC WINAPI ImmCreateIMCC(DWORD size)
3008 return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
3011 /***********************************************************************
3012 * ImmDestroyIMCC(IMM32.@)
3014 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
3016 return GlobalFree(block);
3019 /***********************************************************************
3020 * ImmLockIMCC(IMM32.@)
3022 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
3024 return GlobalLock(imcc);
3027 /***********************************************************************
3028 * ImmUnlockIMCC(IMM32.@)
3030 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
3032 return GlobalUnlock(imcc);
3035 /***********************************************************************
3036 * ImmGetIMCCLockCount(IMM32.@)
3038 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
3040 return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
3043 /***********************************************************************
3044 * ImmReSizeIMCC(IMM32.@)
3046 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
3048 return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
3051 /***********************************************************************
3052 * ImmGetIMCCSize(IMM32.@)
3054 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
3056 return GlobalSize(imcc);
3059 /***********************************************************************
3060 * ImmGenerateMessage(IMM32.@)
3062 BOOL WINAPI ImmGenerateMessage( HIMC himc )
3064 INPUTCONTEXT *ctx;
3066 TRACE( "himc %p\n", himc );
3068 if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
3069 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
3071 while (ctx->dwNumMsgBuf--)
3073 TRANSMSG *msgs, msg;
3074 if (!(msgs = ImmLockIMCC( ctx->hMsgBuf ))) return FALSE;
3075 msg = msgs[0];
3076 memmove( msgs, msgs + 1, ctx->dwNumMsgBuf * sizeof(*msgs) );
3077 ImmUnlockIMCC( ctx->hMsgBuf );
3078 SendMessageW( ctx->hWnd, msg.message, msg.wParam, msg.lParam );
3080 ctx->dwNumMsgBuf++;
3082 return TRUE;
3085 /***********************************************************************
3086 * ImmTranslateMessage(IMM32.@)
3087 * ( Undocumented, call internally and from user32.dll )
3089 BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
3091 union
3093 struct
3095 UINT uMsgCount;
3096 TRANSMSG TransMsg[10];
3098 TRANSMSGLIST list;
3099 } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)};
3100 TRANSMSG *msgs = buffer.TransMsg;
3101 UINT scan, vkey, count, i;
3102 struct imc *data;
3103 struct ime *ime;
3104 BYTE state[256];
3105 WCHAR chr;
3107 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam );
3109 if (msg < WM_KEYDOWN || msg > WM_KEYUP) return FALSE;
3110 if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE;
3111 if (!(ime = imc_select_ime( data ))) return FALSE;
3113 if ((vkey = data->vkey) == VK_PROCESSKEY) return FALSE;
3114 data->vkey = VK_PROCESSKEY;
3115 GetKeyboardState( state );
3116 scan = lparam >> 0x10;
3118 if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3120 if (!ime_is_unicode( ime )) ToAscii( vkey, scan, state, &chr, 0 );
3121 else ToUnicodeEx( vkey, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) );
3122 vkey = MAKELONG( vkey, chr );
3125 count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle );
3126 if (count >= ARRAY_SIZE(buffer.TransMsg)) return 0;
3128 for (i = 0; i < count; i++) PostMessageW( hwnd, msgs[i].message, msgs[i].wParam, msgs[i].lParam );
3129 TRACE( "%u messages generated\n", count );
3131 return count > 0;
3134 /***********************************************************************
3135 * ImmProcessKey(IMM32.@)
3136 * ( Undocumented, called from user32.dll )
3138 BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD unknown )
3140 struct imc *imc;
3141 struct ime *ime;
3142 BYTE state[256];
3143 BOOL ret;
3145 TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd, hkl, vkey, lparam, unknown );
3147 if (hkl != GetKeyboardLayout( 0 )) return FALSE;
3148 if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE;
3149 if (!(ime = imc_select_ime( imc ))) return FALSE;
3151 GetKeyboardState( state );
3153 ret = ime->pImeProcessKey( imc->handle, vkey, lparam, state );
3154 imc->vkey = ret ? vkey : VK_PROCESSKEY;
3156 return ret;
3159 /***********************************************************************
3160 * ImmDisableTextFrameService(IMM32.@)
3162 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3164 FIXME("Stub\n");
3165 return FALSE;
3168 /***********************************************************************
3169 * ImmEnumInputContext(IMM32.@)
3172 BOOL WINAPI ImmEnumInputContext( DWORD thread, IMCENUMPROC callback, LPARAM lparam )
3174 HIMC buffer[256];
3175 NTSTATUS status;
3176 UINT i, size;
3178 TRACE( "thread %lu, callback %p, lparam %#Ix\n", thread, callback, lparam );
3180 if ((status = NtUserBuildHimcList( thread, ARRAY_SIZE(buffer), buffer, &size )))
3182 RtlSetLastWin32Error( RtlNtStatusToDosError( status ) );
3183 WARN( "NtUserBuildHimcList returned %#lx\n", status );
3184 return FALSE;
3187 if (size == ARRAY_SIZE(buffer)) FIXME( "NtUserBuildHimcList returned %u handles\n", size );
3188 for (i = 0; i < size; i++) if (!callback( buffer[i], lparam )) return FALSE;
3190 return TRUE;
3193 /***********************************************************************
3194 * ImmGetHotKey(IMM32.@)
3197 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL *hkl)
3199 FIXME("%lx, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3200 return FALSE;
3203 /***********************************************************************
3204 * ImmDisableLegacyIME(IMM32.@)
3206 BOOL WINAPI ImmDisableLegacyIME(void)
3208 FIXME("stub\n");
3209 return TRUE;
3212 static BOOL is_ime_ui_msg(UINT msg)
3214 switch (msg)
3216 case WM_IME_STARTCOMPOSITION:
3217 case WM_IME_ENDCOMPOSITION:
3218 case WM_IME_COMPOSITION:
3219 case WM_IME_SETCONTEXT:
3220 case WM_IME_NOTIFY:
3221 case WM_IME_CONTROL:
3222 case WM_IME_COMPOSITIONFULL:
3223 case WM_IME_SELECT:
3224 case WM_IME_CHAR:
3225 case WM_IME_REQUEST:
3226 case WM_IME_KEYDOWN:
3227 case WM_IME_KEYUP:
3228 return TRUE;
3229 default:
3230 return msg == WM_MSIME_RECONVERTOPTIONS ||
3231 msg == WM_MSIME_SERVICE ||
3232 msg == WM_MSIME_MOUSE ||
3233 msg == WM_MSIME_RECONVERTREQUEST ||
3234 msg == WM_MSIME_RECONVERT ||
3235 msg == WM_MSIME_QUERYPOSITION ||
3236 msg == WM_MSIME_DOCUMENTFEED;
3240 static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam)
3242 HWND hwnd;
3243 HIMC himc;
3245 switch (wparam)
3247 case IME_INTERNAL_ACTIVATE:
3248 hwnd = (HWND)lparam;
3249 himc = NtUserGetWindowInputContext( hwnd );
3250 ImmSetActiveContext( hwnd, himc, TRUE );
3251 set_ime_ui_window_himc( himc );
3252 break;
3253 case IME_INTERNAL_DEACTIVATE:
3254 hwnd = (HWND)lparam;
3255 himc = NtUserGetWindowInputContext( hwnd );
3256 ImmSetActiveContext( hwnd, himc, FALSE );
3257 break;
3258 case IME_INTERNAL_HKL_ACTIVATE:
3259 ImmEnumInputContext( 0, enum_activate_layout, 0 );
3260 if (!(hwnd = get_ime_ui_window())) break;
3261 SendMessageW( hwnd, WM_IME_SELECT, TRUE, lparam );
3262 break;
3263 case IME_INTERNAL_HKL_DEACTIVATE:
3264 if (!(hwnd = get_ime_ui_window())) break;
3265 SendMessageW( hwnd, WM_IME_SELECT, FALSE, lparam );
3266 break;
3267 default:
3268 FIXME("wparam = %Ix\n", wparam);
3269 break;
3272 return 0;
3275 static void init_messages(void)
3277 static BOOL initialized;
3279 if (initialized) return;
3281 WM_MSIME_SERVICE = RegisterWindowMessageW(L"MSIMEService");
3282 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageW(L"MSIMEReconvertOptions");
3283 WM_MSIME_MOUSE = RegisterWindowMessageW(L"MSIMEMouseOperation");
3284 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageW(L"MSIMEReconvertRequest");
3285 WM_MSIME_RECONVERT = RegisterWindowMessageW(L"MSIMEReconvert");
3286 WM_MSIME_QUERYPOSITION = RegisterWindowMessageW(L"MSIMEQueryPosition");
3287 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageW(L"MSIMEDocumentFeed");
3288 initialized = TRUE;
3291 LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi)
3293 HWND ui_hwnd;
3295 TRACE( "hwnd %p, msg %s, wparam %#Ix, lparam %#Ix, ansi %u\n",
3296 hwnd, debugstr_wm_ime(msg), wparam, lparam, ansi );
3298 switch (msg)
3300 case WM_CREATE:
3301 init_messages();
3302 return TRUE;
3304 case WM_DESTROY:
3306 HWND default_hwnd = ImmGetDefaultIMEWnd(0);
3307 if (!default_hwnd || hwnd == default_hwnd)
3308 imm_couninit_thread(TRUE);
3310 return TRUE;
3312 case WM_IME_INTERNAL:
3313 return ime_internal_msg(wparam, lparam);
3316 if (is_ime_ui_msg(msg))
3318 if ((ui_hwnd = get_ime_ui_window()))
3320 if (ansi)
3321 return SendMessageA(ui_hwnd, msg, wparam, lparam);
3322 else
3323 return SendMessageW(ui_hwnd, msg, wparam, lparam);
3325 return FALSE;
3328 if (ansi)
3329 return DefWindowProcA(hwnd, msg, wparam, lparam);
3330 else
3331 return DefWindowProcW(hwnd, msg, wparam, lparam);