xref: /reactos/dll/win32/imm32/imm.c (revision 0622ce17)
1 /*
2  * IMM32 library
3  *
4  * Copyright 1998 Patrik Stridvall
5  * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #define WIN32_NO_STATUS
23 
24 //#include <stdarg.h>
25 #include <stdio.h>
26 
27 #include <windef.h>
28 #include <winbase.h>
29 //#include "wingdi.h"
30 #include <winuser.h>
31 //#include "winerror.h"
32 #include <wine/debug.h>
33 //#include "imm.h"
34 #include <ddk/imm.h>
35 #include <winnls.h>
36 #include <winreg.h>
37 #include <wine/list.h>
38 #include <wine/unicode.h>
39 
40 WINE_DEFAULT_DEBUG_CHANNEL(imm);
41 
42 #define IMM_INIT_MAGIC 0x19650412
43 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
44 
45 #define MAKE_FUNCPTR(f) typeof(f) * p##f
46 typedef struct _tagImmHkl{
47     struct list entry;
48     HKL         hkl;
49     HMODULE     hIME;
50     IMEINFO     imeInfo;
51     WCHAR       imeClassName[17]; /* 16 character max */
52     ULONG       uSelected;
53     HWND        UIWnd;
54 
55     /* Function Pointers */
56     MAKE_FUNCPTR(ImeInquire);
57     MAKE_FUNCPTR(ImeConfigure);
58     MAKE_FUNCPTR(ImeDestroy);
59     MAKE_FUNCPTR(ImeEscape);
60     MAKE_FUNCPTR(ImeSelect);
61     MAKE_FUNCPTR(ImeSetActiveContext);
62     MAKE_FUNCPTR(ImeToAsciiEx);
63     MAKE_FUNCPTR(NotifyIME);
64     MAKE_FUNCPTR(ImeRegisterWord);
65     MAKE_FUNCPTR(ImeUnregisterWord);
66     MAKE_FUNCPTR(ImeEnumRegisterWord);
67     MAKE_FUNCPTR(ImeSetCompositionString);
68     MAKE_FUNCPTR(ImeConversionList);
69     MAKE_FUNCPTR(ImeProcessKey);
70     MAKE_FUNCPTR(ImeGetRegisterWordStyle);
71     MAKE_FUNCPTR(ImeGetImeMenuItems);
72 } ImmHkl;
73 #undef MAKE_FUNCPTR
74 
75 typedef struct tagInputContextData
76 {
77         DWORD           dwLock;
78         INPUTCONTEXT    IMC;
79         DWORD           threadID;
80 
81         ImmHkl          *immKbd;
82         UINT            lastVK;
83         BOOL            threadDefault;
84         DWORD           magic;
85 } InputContextData;
86 
87 #define WINE_IMC_VALID_MAGIC 0x56434D49
88 
89 typedef struct _tagTRANSMSG {
90     UINT message;
91     WPARAM wParam;
92     LPARAM lParam;
93 } TRANSMSG, *LPTRANSMSG;
94 
95 typedef struct _tagIMMThreadData {
96     struct list entry;
97     DWORD threadID;
98     HIMC defaultContext;
99     HWND hwndDefault;
100     BOOL disableIME;
101     DWORD windowRefs;
102 } IMMThreadData;
103 
104 static struct list ImmHklList = LIST_INIT(ImmHklList);
105 static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
106 
107 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
108 
109 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
110 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
111 static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
112 
113 static const WCHAR szwIME[] = {'I','M','E',0};
114 static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0};
115 
116 static CRITICAL_SECTION threaddata_cs;
117 static CRITICAL_SECTION_DEBUG critsect_debug =
118 {
119     0, 0, &threaddata_cs,
120     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
121       0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
122 };
123 static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
124 static BOOL disable_ime;
125 
126 #define is_himc_ime_unicode(p)  (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE)
127 #define is_kbd_ime_unicode(p)  (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
128 
129 static BOOL IMM_DestroyContext(HIMC hIMC);
130 static InputContextData* get_imc_data(HIMC hIMC);
131 
132 static inline WCHAR *strdupAtoW( const char *str )
133 {
134     WCHAR *ret = NULL;
135     if (str)
136     {
137         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
138         if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
139             MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
140     }
141     return ret;
142 }
143 
144 static inline CHAR *strdupWtoA( const WCHAR *str )
145 {
146     CHAR *ret = NULL;
147     if (str)
148     {
149         DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
150         if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
151             WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
152     }
153     return ret;
154 }
155 
156 static DWORD convert_candidatelist_WtoA(
157         LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
158 {
159     DWORD ret, i, len;
160 
161     ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
162     if ( lpDst && dwBufLen > 0 )
163     {
164         *lpDst = *lpSrc;
165         lpDst->dwOffset[0] = ret;
166     }
167 
168     for ( i = 0; i < lpSrc->dwCount; i++)
169     {
170         LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
171 
172         if ( lpDst && dwBufLen > 0 )
173         {
174             LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
175 
176             len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
177                                       (LPSTR)dest, dwBufLen, NULL, NULL);
178 
179             if ( i + 1 < lpSrc->dwCount )
180                 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
181             dwBufLen -= len * sizeof(char);
182         }
183         else
184             len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
185 
186         ret += len * sizeof(char);
187     }
188 
189     if ( lpDst )
190         lpDst->dwSize = ret;
191 
192     return ret;
193 }
194 
195 static DWORD convert_candidatelist_AtoW(
196         LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
197 {
198     DWORD ret, i, len;
199 
200     ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
201     if ( lpDst && dwBufLen > 0 )
202     {
203         *lpDst = *lpSrc;
204         lpDst->dwOffset[0] = ret;
205     }
206 
207     for ( i = 0; i < lpSrc->dwCount; i++)
208     {
209         LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
210 
211         if ( lpDst && dwBufLen > 0 )
212         {
213             LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
214 
215             len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
216                                       (LPWSTR)dest, dwBufLen);
217 
218             if ( i + 1 < lpSrc->dwCount )
219                 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
220             dwBufLen -= len * sizeof(WCHAR);
221         }
222         else
223             len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
224 
225         ret += len * sizeof(WCHAR);
226     }
227 
228     if ( lpDst )
229         lpDst->dwSize = ret;
230 
231     return ret;
232 }
233 
234 static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
235 {
236     IMMThreadData *data;
237     DWORD process;
238 
239     if (hwnd)
240     {
241         if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL;
242         if (process != GetCurrentProcessId()) return NULL;
243     }
244     else if (thread)
245     {
246         HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread);
247         if (!h) return NULL;
248         process = GetProcessIdOfThread(h);
249         CloseHandle(h);
250         if (process != GetCurrentProcessId()) return NULL;
251     }
252     else
253         thread = GetCurrentThreadId();
254 
255     EnterCriticalSection(&threaddata_cs);
256     LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
257         if (data->threadID == thread) return data;
258 
259     data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
260     data->threadID = thread;
261     list_add_head(&ImmThreadDataList,&data->entry);
262     TRACE("Thread Data Created (%x)\n",thread);
263     return data;
264 }
265 
266 static BOOL IMM_IsDefaultContext(HIMC imc)
267 {
268     InputContextData *data = get_imc_data(imc);
269 
270     if (!data)
271         return FALSE;
272 
273     return data->threadDefault;
274 }
275 
276 static void IMM_FreeThreadData(void)
277 {
278     IMMThreadData *data;
279 
280     EnterCriticalSection(&threaddata_cs);
281     LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
282     {
283         if (data->threadID == GetCurrentThreadId())
284         {
285             list_remove(&data->entry);
286             LeaveCriticalSection(&threaddata_cs);
287             IMM_DestroyContext(data->defaultContext);
288             HeapFree(GetProcessHeap(),0,data);
289             TRACE("Thread Data Destroyed\n");
290             return;
291         }
292     }
293     LeaveCriticalSection(&threaddata_cs);
294 }
295 
296 static HMODULE load_graphics_driver(void)
297 {
298     static const WCHAR display_device_guid_propW[] = {
299         '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
300         'd','e','v','i','c','e','_','g','u','i','d',0 };
301     static const WCHAR key_pathW[] = {
302         'S','y','s','t','e','m','\\',
303         'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
304         'C','o','n','t','r','o','l','\\',
305         'V','i','d','e','o','\\','{',0};
306     static const WCHAR displayW[] = {'}','\\','0','0','0','0',0};
307     static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0};
308 
309     HMODULE ret = 0;
310     HKEY hkey;
311     DWORD size;
312     WCHAR path[MAX_PATH];
313     WCHAR key[(sizeof(key_pathW) + sizeof(displayW)) / sizeof(WCHAR) + 40];
314     UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW ));
315 
316     if (!guid_atom) return 0;
317     memcpy( key, key_pathW, sizeof(key_pathW) );
318     if (!GlobalGetAtomNameW( guid_atom, key + strlenW(key), 40 )) return 0;
319     strcatW( key, displayW );
320     if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
321     size = sizeof(path);
322     if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path );
323     RegCloseKey( hkey );
324     TRACE( "%s %p\n", debugstr_w(path), ret );
325     return ret;
326 }
327 
328 /* ImmHkl loading and freeing */
329 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
330 static ImmHkl *IMM_GetImmHkl(HKL hkl)
331 {
332     ImmHkl *ptr;
333     WCHAR filename[MAX_PATH];
334 
335     TRACE("Seeking ime for keyboard %p\n",hkl);
336 
337     LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
338     {
339         if (ptr->hkl == hkl)
340             return ptr;
341     }
342     /* not found... create it */
343 
344     ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
345 
346     ptr->hkl = hkl;
347     if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
348     if (!ptr->hIME) ptr->hIME = load_graphics_driver();
349     if (ptr->hIME)
350     {
351         LOAD_FUNCPTR(ImeInquire);
352         if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
353         {
354             FreeLibrary(ptr->hIME);
355             ptr->hIME = NULL;
356         }
357         else
358         {
359             LOAD_FUNCPTR(ImeDestroy);
360             LOAD_FUNCPTR(ImeSelect);
361             if (!ptr->pImeSelect || !ptr->pImeDestroy)
362             {
363                 FreeLibrary(ptr->hIME);
364                 ptr->hIME = NULL;
365             }
366             else
367             {
368                 LOAD_FUNCPTR(ImeConfigure);
369                 LOAD_FUNCPTR(ImeEscape);
370                 LOAD_FUNCPTR(ImeSetActiveContext);
371                 LOAD_FUNCPTR(ImeToAsciiEx);
372                 LOAD_FUNCPTR(NotifyIME);
373                 LOAD_FUNCPTR(ImeRegisterWord);
374                 LOAD_FUNCPTR(ImeUnregisterWord);
375                 LOAD_FUNCPTR(ImeEnumRegisterWord);
376                 LOAD_FUNCPTR(ImeSetCompositionString);
377                 LOAD_FUNCPTR(ImeConversionList);
378                 LOAD_FUNCPTR(ImeProcessKey);
379                 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
380                 LOAD_FUNCPTR(ImeGetImeMenuItems);
381                 /* make sure our classname is WCHAR */
382                 if (!is_kbd_ime_unicode(ptr))
383                 {
384                     WCHAR bufW[17];
385                     MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
386                                         -1, bufW, 17);
387                     lstrcpyW(ptr->imeClassName, bufW);
388                 }
389             }
390         }
391     }
392     list_add_head(&ImmHklList,&ptr->entry);
393 
394     return ptr;
395 }
396 #undef LOAD_FUNCPTR
397 
398 HWND WINAPI __wine_get_ui_window(HKL hkl)
399 {
400     ImmHkl *immHkl = IMM_GetImmHkl(hkl);
401     return immHkl->UIWnd;
402 }
403 
404 static void IMM_FreeAllImmHkl(void)
405 {
406     ImmHkl *ptr,*cursor2;
407 
408     LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
409     {
410         list_remove(&ptr->entry);
411         if (ptr->hIME)
412         {
413             ptr->pImeDestroy(1);
414             FreeLibrary(ptr->hIME);
415         }
416         if (ptr->UIWnd)
417             DestroyWindow(ptr->UIWnd);
418         HeapFree(GetProcessHeap(),0,ptr);
419     }
420 }
421 
422 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
423 {
424     TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
425     switch (fdwReason)
426     {
427         case DLL_PROCESS_ATTACH:
428             if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
429             {
430                 return FALSE;
431             }
432             break;
433         case DLL_THREAD_ATTACH:
434             break;
435         case DLL_THREAD_DETACH:
436             IMM_FreeThreadData();
437             break;
438         case DLL_PROCESS_DETACH:
439             if (lpReserved) break;
440             IMM_FreeThreadData();
441             IMM_FreeAllImmHkl();
442             break;
443     }
444     return TRUE;
445 }
446 
447 /* for posting messages as the IME */
448 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
449 {
450     HWND target = GetFocus();
451     if (!target)
452        PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
453     else
454        PostMessageW(target, msg, wParam, lParam);
455 }
456 
457 /* for sending messages as the IME */
458 static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
459 {
460     HWND target = GetFocus();
461     if (!target)
462        SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
463     else
464        SendMessageW(target, msg, wParam, lParam);
465 }
466 
467 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
468 {
469     HWND target;
470 
471     target = data->IMC.hWnd;
472     if (!target) target = GetFocus();
473 
474     if (target)
475        return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
476 
477     return 0;
478 }
479 
480 static HIMCC ImmCreateBlankCompStr(void)
481 {
482     HIMCC rc;
483     LPCOMPOSITIONSTRING ptr;
484     rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
485     ptr = ImmLockIMCC(rc);
486     memset(ptr,0,sizeof(COMPOSITIONSTRING));
487     ptr->dwSize = sizeof(COMPOSITIONSTRING);
488     ImmUnlockIMCC(rc);
489     return rc;
490 }
491 
492 static InputContextData* get_imc_data(HIMC hIMC)
493 {
494     InputContextData *data = hIMC;
495 
496     if (hIMC == NULL)
497         return NULL;
498 
499     if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
500     {
501         SetLastError(ERROR_INVALID_HANDLE);
502         return NULL;
503     }
504     return data;
505 }
506 
507 static HIMC get_default_context( HWND hwnd )
508 {
509     HIMC ret;
510     IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 );
511 
512     if (!thread_data) return 0;
513 
514     if (thread_data->defaultContext)
515     {
516         ret = thread_data->defaultContext;
517         LeaveCriticalSection(&threaddata_cs);
518         return ret;
519     }
520 
521     /* can't create a default context in another thread */
522     if (thread_data->threadID != GetCurrentThreadId())
523     {
524         LeaveCriticalSection(&threaddata_cs);
525         return 0;
526     }
527 
528     LeaveCriticalSection(&threaddata_cs);
529 
530     ret = ImmCreateContext();
531     if (!ret) return 0;
532     ((InputContextData*)ret)->threadDefault = TRUE;
533 
534     /* thread_data is in the current thread so we can assume it's still valid */
535     EnterCriticalSection(&threaddata_cs);
536 
537     if (thread_data->defaultContext) /* someone beat us */
538     {
539         IMM_DestroyContext( ret );
540         ret = thread_data->defaultContext;
541     }
542     else thread_data->defaultContext = ret;
543 
544     LeaveCriticalSection(&threaddata_cs);
545     return ret;
546 }
547 
548 static BOOL IMM_IsCrossThreadAccess(HWND hWnd,  HIMC hIMC)
549 {
550     InputContextData *data;
551 
552     if (hWnd)
553     {
554         DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
555         if (thread != GetCurrentThreadId()) return TRUE;
556     }
557     data = get_imc_data(hIMC);
558     if (data && data->threadID != GetCurrentThreadId())
559         return TRUE;
560 
561     return FALSE;
562 }
563 
564 /***********************************************************************
565  *		ImmAssociateContext (IMM32.@)
566  */
567 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
568 {
569     HIMC old = NULL;
570     InputContextData *data = get_imc_data(hIMC);
571 
572     TRACE("(%p, %p):\n", hWnd, hIMC);
573 
574     if(hIMC && !data)
575         return NULL;
576 
577     /*
578      * If already associated just return
579      */
580     if (hIMC && data->IMC.hWnd == hWnd)
581         return hIMC;
582 
583     if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
584         return NULL;
585 
586     if (hWnd)
587     {
588         HIMC defaultContext = get_default_context( hWnd );
589         old = RemovePropW(hWnd,szwWineIMCProperty);
590 
591         if (old == NULL)
592             old = defaultContext;
593         else if (old == (HIMC)-1)
594             old = NULL;
595 
596         if (hIMC != defaultContext)
597         {
598             if (hIMC == NULL) /* Meaning disable imm for that window*/
599                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
600             else
601                 SetPropW(hWnd,szwWineIMCProperty,hIMC);
602         }
603 
604         if (old)
605         {
606             InputContextData *old_data = old;
607             if (old_data->IMC.hWnd == hWnd)
608                 old_data->IMC.hWnd = NULL;
609         }
610     }
611 
612     if (!hIMC)
613         return old;
614 
615     SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
616     data->IMC.hWnd = hWnd;
617     SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
618 
619     return old;
620 }
621 
622 
623 /*
624  * Helper function for ImmAssociateContextEx
625  */
626 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
627 {
628     HIMC hImc = (HIMC)lParam;
629     ImmAssociateContext(hwnd,hImc);
630     return TRUE;
631 }
632 
633 /***********************************************************************
634  *              ImmAssociateContextEx (IMM32.@)
635  */
636 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
637 {
638     TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
639 
640     if (!hWnd)
641         return FALSE;
642 
643     switch (dwFlags)
644     {
645     case 0:
646         ImmAssociateContext(hWnd,hIMC);
647         return TRUE;
648     case IACE_DEFAULT:
649     {
650         HIMC defaultContext = get_default_context( hWnd );
651         if (!defaultContext) return FALSE;
652         ImmAssociateContext(hWnd,defaultContext);
653         return TRUE;
654     }
655     case IACE_IGNORENOCONTEXT:
656         if (GetPropW(hWnd,szwWineIMCProperty))
657             ImmAssociateContext(hWnd,hIMC);
658         return TRUE;
659     case IACE_CHILDREN:
660         EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
661         return TRUE;
662     default:
663         FIXME("Unknown dwFlags 0x%x\n",dwFlags);
664         return FALSE;
665     }
666 }
667 
668 /***********************************************************************
669  *		ImmConfigureIMEA (IMM32.@)
670  */
671 BOOL WINAPI ImmConfigureIMEA(
672   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
673 {
674     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
675 
676     TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
677 
678     if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
679         return FALSE;
680 
681     if (immHkl->hIME && immHkl->pImeConfigure)
682     {
683         if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
684             return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
685         else
686         {
687             REGISTERWORDW rww;
688             REGISTERWORDA *rwa = lpData;
689             BOOL rc;
690 
691             rww.lpReading = strdupAtoW(rwa->lpReading);
692             rww.lpWord = strdupAtoW(rwa->lpWord);
693             rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
694             HeapFree(GetProcessHeap(),0,rww.lpReading);
695             HeapFree(GetProcessHeap(),0,rww.lpWord);
696             return rc;
697         }
698     }
699     else
700         return FALSE;
701 }
702 
703 /***********************************************************************
704  *		ImmConfigureIMEW (IMM32.@)
705  */
706 BOOL WINAPI ImmConfigureIMEW(
707   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
708 {
709     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
710 
711     TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
712 
713     if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
714         return FALSE;
715 
716     if (immHkl->hIME && immHkl->pImeConfigure)
717     {
718         if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
719             return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
720         else
721         {
722             REGISTERWORDW *rww = lpData;
723             REGISTERWORDA rwa;
724             BOOL rc;
725 
726             rwa.lpReading = strdupWtoA(rww->lpReading);
727             rwa.lpWord = strdupWtoA(rww->lpWord);
728             rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
729             HeapFree(GetProcessHeap(),0,rwa.lpReading);
730             HeapFree(GetProcessHeap(),0,rwa.lpWord);
731             return rc;
732         }
733     }
734     else
735         return FALSE;
736 }
737 
738 /***********************************************************************
739  *		ImmCreateContext (IMM32.@)
740  */
741 HIMC WINAPI ImmCreateContext(void)
742 {
743     InputContextData *new_context;
744     LPGUIDELINE gl;
745     LPCANDIDATEINFO ci;
746     int i;
747 
748     new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
749 
750     /* Load the IME */
751     new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
752 
753     if (!new_context->immKbd->hIME)
754     {
755         TRACE("IME dll could not be loaded\n");
756         HeapFree(GetProcessHeap(),0,new_context);
757         return 0;
758     }
759 
760     /* the HIMCCs are never NULL */
761     new_context->IMC.hCompStr = ImmCreateBlankCompStr();
762     new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
763     new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
764     ci = ImmLockIMCC(new_context->IMC.hCandInfo);
765     memset(ci,0,sizeof(CANDIDATEINFO));
766     ci->dwSize = sizeof(CANDIDATEINFO);
767     ImmUnlockIMCC(new_context->IMC.hCandInfo);
768     new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
769     gl = ImmLockIMCC(new_context->IMC.hGuideLine);
770     memset(gl,0,sizeof(GUIDELINE));
771     gl->dwSize = sizeof(GUIDELINE);
772     ImmUnlockIMCC(new_context->IMC.hGuideLine);
773 
774     for (i = 0; i < sizeof(new_context->IMC.cfCandForm) / sizeof(CANDIDATEFORM); i++)
775         new_context->IMC.cfCandForm[i].dwIndex = ~0u;
776 
777     /* Initialize the IME Private */
778     new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
779 
780     new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps;
781     new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps;
782 
783     if (!new_context->immKbd->pImeSelect(new_context, TRUE))
784     {
785         TRACE("Selection of IME failed\n");
786         IMM_DestroyContext(new_context);
787         return 0;
788     }
789     new_context->threadID = GetCurrentThreadId();
790     SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
791 
792     new_context->immKbd->uSelected++;
793     TRACE("Created context %p\n",new_context);
794 
795     new_context->magic = WINE_IMC_VALID_MAGIC;
796     return new_context;
797 }
798 
799 static BOOL IMM_DestroyContext(HIMC hIMC)
800 {
801     InputContextData *data = get_imc_data(hIMC);
802 
803     TRACE("Destroying %p\n",hIMC);
804 
805     if (!data)
806         return FALSE;
807 
808     data->immKbd->uSelected --;
809     data->immKbd->pImeSelect(hIMC, FALSE);
810     SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
811 
812     ImmDestroyIMCC(data->IMC.hCompStr);
813     ImmDestroyIMCC(data->IMC.hCandInfo);
814     ImmDestroyIMCC(data->IMC.hGuideLine);
815     ImmDestroyIMCC(data->IMC.hPrivate);
816     ImmDestroyIMCC(data->IMC.hMsgBuf);
817 
818     data->magic = 0;
819     HeapFree(GetProcessHeap(),0,data);
820 
821     return TRUE;
822 }
823 
824 /***********************************************************************
825  *		ImmDestroyContext (IMM32.@)
826  */
827 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
828 {
829     if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
830         return IMM_DestroyContext(hIMC);
831     else
832         return FALSE;
833 }
834 
835 /***********************************************************************
836  *		ImmDisableIME (IMM32.@)
837  */
838 BOOL WINAPI ImmDisableIME(DWORD idThread)
839 {
840     if (idThread == (DWORD)-1)
841         disable_ime = TRUE;
842     else {
843         IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread);
844         if (!thread_data) return FALSE;
845         thread_data->disableIME = TRUE;
846         LeaveCriticalSection(&threaddata_cs);
847     }
848     return TRUE;
849 }
850 
851 /***********************************************************************
852  *		ImmEnumRegisterWordA (IMM32.@)
853  */
854 UINT WINAPI ImmEnumRegisterWordA(
855   HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
856   LPCSTR lpszReading, DWORD dwStyle,
857   LPCSTR lpszRegister, LPVOID lpData)
858 {
859     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
860     TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
861         debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
862     if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
863     {
864         if (!is_kbd_ime_unicode(immHkl))
865             return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
866                 (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
867         else
868         {
869             LPWSTR lpszwReading = strdupAtoW(lpszReading);
870             LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
871             BOOL rc;
872 
873             rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
874                                               lpszwReading, dwStyle, lpszwRegister,
875                                               lpData);
876 
877             HeapFree(GetProcessHeap(),0,lpszwReading);
878             HeapFree(GetProcessHeap(),0,lpszwRegister);
879             return rc;
880         }
881     }
882     else
883         return 0;
884 }
885 
886 /***********************************************************************
887  *		ImmEnumRegisterWordW (IMM32.@)
888  */
889 UINT WINAPI ImmEnumRegisterWordW(
890   HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
891   LPCWSTR lpszReading, DWORD dwStyle,
892   LPCWSTR lpszRegister, LPVOID lpData)
893 {
894     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
895     TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
896         debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
897     if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
898     {
899         if (is_kbd_ime_unicode(immHkl))
900             return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
901                                             lpszRegister, lpData);
902         else
903         {
904             LPSTR lpszaReading = strdupWtoA(lpszReading);
905             LPSTR lpszaRegister = strdupWtoA(lpszRegister);
906             BOOL rc;
907 
908             rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
909                                               dwStyle, (LPCWSTR)lpszaRegister, lpData);
910 
911             HeapFree(GetProcessHeap(),0,lpszaReading);
912             HeapFree(GetProcessHeap(),0,lpszaRegister);
913             return rc;
914         }
915     }
916     else
917         return 0;
918 }
919 
920 static inline BOOL EscapeRequiresWA(UINT uEscape)
921 {
922         if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
923             uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
924             uEscape == IME_ESC_IME_NAME ||
925             uEscape == IME_ESC_GETHELPFILENAME)
926         return TRUE;
927     return FALSE;
928 }
929 
930 /***********************************************************************
931  *		ImmEscapeA (IMM32.@)
932  */
933 LRESULT WINAPI ImmEscapeA(
934   HKL hKL, HIMC hIMC,
935   UINT uEscape, LPVOID lpData)
936 {
937     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
938     TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
939 
940     if (immHkl->hIME && immHkl->pImeEscape)
941     {
942         if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
943             return immHkl->pImeEscape(hIMC,uEscape,lpData);
944         else
945         {
946             WCHAR buffer[81]; /* largest required buffer should be 80 */
947             LRESULT rc;
948             if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
949             {
950                 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
951                 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
952             }
953             else
954             {
955                 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
956                 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
957             }
958             return rc;
959         }
960     }
961     else
962         return 0;
963 }
964 
965 /***********************************************************************
966  *		ImmEscapeW (IMM32.@)
967  */
968 LRESULT WINAPI ImmEscapeW(
969   HKL hKL, HIMC hIMC,
970   UINT uEscape, LPVOID lpData)
971 {
972     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
973     TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
974 
975     if (immHkl->hIME && immHkl->pImeEscape)
976     {
977         if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
978             return immHkl->pImeEscape(hIMC,uEscape,lpData);
979         else
980         {
981             CHAR buffer[81]; /* largest required buffer should be 80 */
982             LRESULT rc;
983             if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
984             {
985                 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
986                 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
987             }
988             else
989             {
990                 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
991                 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
992             }
993             return rc;
994         }
995     }
996     else
997         return 0;
998 }
999 
1000 /***********************************************************************
1001  *		ImmGetCandidateListA (IMM32.@)
1002  */
1003 DWORD WINAPI ImmGetCandidateListA(
1004   HIMC hIMC, DWORD dwIndex,
1005   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1006 {
1007     InputContextData *data = get_imc_data(hIMC);
1008     LPCANDIDATEINFO candinfo;
1009     LPCANDIDATELIST candlist;
1010     DWORD ret = 0;
1011 
1012     TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
1013 
1014     if (!data || !data->IMC.hCandInfo)
1015        return 0;
1016 
1017     candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1018     if ( dwIndex >= candinfo->dwCount ||
1019          dwIndex >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) )
1020         goto done;
1021 
1022     candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1023     if ( !candlist->dwSize || !candlist->dwCount )
1024         goto done;
1025 
1026     if ( !is_himc_ime_unicode(data) )
1027     {
1028         ret = candlist->dwSize;
1029         if ( lpCandList && dwBufLen >= ret )
1030             memcpy(lpCandList, candlist, ret);
1031     }
1032     else
1033         ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
1034 
1035 done:
1036     ImmUnlockIMCC(data->IMC.hCandInfo);
1037     return ret;
1038 }
1039 
1040 /***********************************************************************
1041  *		ImmGetCandidateListCountA (IMM32.@)
1042  */
1043 DWORD WINAPI ImmGetCandidateListCountA(
1044   HIMC hIMC, LPDWORD lpdwListCount)
1045 {
1046     InputContextData *data = get_imc_data(hIMC);
1047     LPCANDIDATEINFO candinfo;
1048     DWORD ret, count;
1049 
1050     TRACE("%p, %p\n", hIMC, lpdwListCount);
1051 
1052     if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1053        return 0;
1054 
1055     candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1056 
1057     *lpdwListCount = count = candinfo->dwCount;
1058 
1059     if ( !is_himc_ime_unicode(data) )
1060         ret = candinfo->dwSize;
1061     else
1062     {
1063         ret = sizeof(CANDIDATEINFO);
1064         while ( count-- )
1065             ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
1066     }
1067 
1068     ImmUnlockIMCC(data->IMC.hCandInfo);
1069     return ret;
1070 }
1071 
1072 /***********************************************************************
1073  *		ImmGetCandidateListCountW (IMM32.@)
1074  */
1075 DWORD WINAPI ImmGetCandidateListCountW(
1076   HIMC hIMC, LPDWORD lpdwListCount)
1077 {
1078     InputContextData *data = get_imc_data(hIMC);
1079     LPCANDIDATEINFO candinfo;
1080     DWORD ret, count;
1081 
1082     TRACE("%p, %p\n", hIMC, lpdwListCount);
1083 
1084     if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1085        return 0;
1086 
1087     candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1088 
1089     *lpdwListCount = count = candinfo->dwCount;
1090 
1091     if ( is_himc_ime_unicode(data) )
1092         ret = candinfo->dwSize;
1093     else
1094     {
1095         ret = sizeof(CANDIDATEINFO);
1096         while ( count-- )
1097             ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
1098     }
1099 
1100     ImmUnlockIMCC(data->IMC.hCandInfo);
1101     return ret;
1102 }
1103 
1104 /***********************************************************************
1105  *		ImmGetCandidateListW (IMM32.@)
1106  */
1107 DWORD WINAPI ImmGetCandidateListW(
1108   HIMC hIMC, DWORD dwIndex,
1109   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1110 {
1111     InputContextData *data = get_imc_data(hIMC);
1112     LPCANDIDATEINFO candinfo;
1113     LPCANDIDATELIST candlist;
1114     DWORD ret = 0;
1115 
1116     TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
1117 
1118     if (!data || !data->IMC.hCandInfo)
1119        return 0;
1120 
1121     candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1122     if ( dwIndex >= candinfo->dwCount ||
1123          dwIndex >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) )
1124         goto done;
1125 
1126     candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1127     if ( !candlist->dwSize || !candlist->dwCount )
1128         goto done;
1129 
1130     if ( is_himc_ime_unicode(data) )
1131     {
1132         ret = candlist->dwSize;
1133         if ( lpCandList && dwBufLen >= ret )
1134             memcpy(lpCandList, candlist, ret);
1135     }
1136     else
1137         ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
1138 
1139 done:
1140     ImmUnlockIMCC(data->IMC.hCandInfo);
1141     return ret;
1142 }
1143 
1144 /***********************************************************************
1145  *		ImmGetCandidateWindow (IMM32.@)
1146  */
1147 BOOL WINAPI ImmGetCandidateWindow(
1148   HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
1149 {
1150     InputContextData *data = get_imc_data(hIMC);
1151 
1152     TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate);
1153 
1154     if (!data || !lpCandidate)
1155         return FALSE;
1156 
1157     if ( dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) )
1158         return FALSE;
1159 
1160     if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex)
1161         return FALSE;
1162 
1163     *lpCandidate = data->IMC.cfCandForm[dwIndex];
1164 
1165     return TRUE;
1166 }
1167 
1168 /***********************************************************************
1169  *		ImmGetCompositionFontA (IMM32.@)
1170  */
1171 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1172 {
1173     LOGFONTW lfW;
1174     BOOL rc;
1175 
1176     TRACE("(%p, %p):\n", hIMC, lplf);
1177 
1178     rc = ImmGetCompositionFontW(hIMC,&lfW);
1179     if (!rc || !lplf)
1180         return FALSE;
1181 
1182     memcpy(lplf,&lfW,sizeof(LOGFONTA));
1183     WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1184                         LF_FACESIZE, NULL, NULL);
1185     return TRUE;
1186 }
1187 
1188 /***********************************************************************
1189  *		ImmGetCompositionFontW (IMM32.@)
1190  */
1191 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1192 {
1193     InputContextData *data = get_imc_data(hIMC);
1194 
1195     TRACE("(%p, %p):\n", hIMC, lplf);
1196 
1197     if (!data || !lplf)
1198         return FALSE;
1199 
1200     *lplf = data->IMC.lfFont.W;
1201 
1202     return TRUE;
1203 }
1204 
1205 
1206 /* Helpers for the GetCompositionString functions */
1207 
1208 static INT CopyCompStringIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE target, INT tlen,
1209                                      BOOL unicode )
1210 {
1211     INT rc;
1212 
1213     if (is_himc_ime_unicode(data) && !unicode)
1214         rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)source, slen, (LPSTR)target, tlen, NULL, NULL);
1215     else if (!is_himc_ime_unicode(data) && unicode)
1216         rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)source, slen, (LPWSTR)target, tlen) * sizeof(WCHAR);
1217     else
1218     {
1219         int dlen = (unicode)?sizeof(WCHAR):sizeof(CHAR);
1220         memcpy( target, source, min(slen,tlen)*dlen);
1221         rc = slen*dlen;
1222     }
1223 
1224     return rc;
1225 }
1226 
1227 static INT CopyCompAttrIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, INT sslen,
1228                                    LPBYTE target, INT tlen, BOOL unicode )
1229 {
1230     INT rc;
1231 
1232     if (is_himc_ime_unicode(data) && !unicode)
1233     {
1234         rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, sslen, NULL, 0, NULL, NULL);
1235         if (tlen)
1236         {
1237             const BYTE *src = source;
1238             LPBYTE dst = target;
1239             int i, j = 0, k = 0;
1240 
1241             if (rc < tlen)
1242                 tlen = rc;
1243             for (i = 0; i < sslen; ++i)
1244             {
1245                 int len;
1246 
1247                 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)ssource + i, 1,
1248                                           NULL, 0, NULL, NULL);
1249                 for (; len > 0; --len)
1250                 {
1251                     dst[j++] = src[k];
1252 
1253                     if (j >= tlen)
1254                         goto end;
1255                 }
1256                 ++k;
1257             }
1258         end:
1259             rc = j;
1260         }
1261     }
1262     else if (!is_himc_ime_unicode(data) && unicode)
1263     {
1264         rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, sslen, NULL, 0);
1265         if (tlen)
1266         {
1267             const BYTE *src = source;
1268             LPBYTE dst = target;
1269             int i, j = 0;
1270 
1271             if (rc < tlen)
1272                 tlen = rc;
1273             for (i = 0; i < sslen; ++i)
1274             {
1275                 if (IsDBCSLeadByte(((LPSTR)ssource)[i]))
1276                     continue;
1277 
1278                 dst[j++] = src[i];
1279 
1280                 if (j >= tlen)
1281                     break;
1282             }
1283             rc = j;
1284         }
1285     }
1286     else
1287     {
1288         memcpy( target, source, min(slen,tlen));
1289         rc = slen;
1290     }
1291 
1292     return rc;
1293 }
1294 
1295 static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
1296                                      LPBYTE target, INT tlen, BOOL unicode )
1297 {
1298     INT rc;
1299 
1300     if (is_himc_ime_unicode(data) && !unicode)
1301     {
1302         if (tlen)
1303         {
1304             int i;
1305 
1306             if (slen < tlen)
1307                 tlen = slen;
1308             tlen /= sizeof (DWORD);
1309             for (i = 0; i < tlen; ++i)
1310             {
1311                 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1312                                                           ((DWORD *)source)[i],
1313                                                           NULL, 0,
1314                                                           NULL, NULL);
1315             }
1316             rc = sizeof (DWORD) * i;
1317         }
1318         else
1319             rc = slen;
1320     }
1321     else if (!is_himc_ime_unicode(data) && unicode)
1322     {
1323         if (tlen)
1324         {
1325             int i;
1326 
1327             if (slen < tlen)
1328                 tlen = slen;
1329             tlen /= sizeof (DWORD);
1330             for (i = 0; i < tlen; ++i)
1331             {
1332                 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1333                                                           ((DWORD *)source)[i],
1334                                                           NULL, 0);
1335             }
1336             rc = sizeof (DWORD) * i;
1337         }
1338         else
1339             rc = slen;
1340     }
1341     else
1342     {
1343         memcpy( target, source, min(slen,tlen));
1344         rc = slen;
1345     }
1346 
1347     return rc;
1348 }
1349 
1350 static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
1351 {
1352     int rc;
1353 
1354     if (is_himc_ime_unicode(data) && !unicode)
1355     {
1356         rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1357     }
1358     else if (!is_himc_ime_unicode(data) && unicode)
1359     {
1360         rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1361     }
1362     else
1363         rc = offset;
1364 
1365     return rc;
1366 }
1367 
1368 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1369                                       DWORD dwBufLen, BOOL unicode)
1370 {
1371     LONG rc = 0;
1372     InputContextData *data = get_imc_data(hIMC);
1373     LPCOMPOSITIONSTRING compstr;
1374     LPBYTE compdata;
1375 
1376     TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1377 
1378     if (!data)
1379        return FALSE;
1380 
1381     if (!data->IMC.hCompStr)
1382        return FALSE;
1383 
1384     compdata = ImmLockIMCC(data->IMC.hCompStr);
1385     compstr = (LPCOMPOSITIONSTRING)compdata;
1386 
1387     switch (dwIndex)
1388     {
1389     case GCS_RESULTSTR:
1390         TRACE("GCS_RESULTSTR\n");
1391         rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1392         break;
1393     case GCS_COMPSTR:
1394         TRACE("GCS_COMPSTR\n");
1395         rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1396         break;
1397     case GCS_COMPATTR:
1398         TRACE("GCS_COMPATTR\n");
1399         rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1400                                      compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1401                                      lpBuf, dwBufLen, unicode);
1402         break;
1403     case GCS_COMPCLAUSE:
1404         TRACE("GCS_COMPCLAUSE\n");
1405         rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1406                                        compdata + compstr->dwCompStrOffset,
1407                                        lpBuf, dwBufLen, unicode);
1408         break;
1409     case GCS_RESULTCLAUSE:
1410         TRACE("GCS_RESULTCLAUSE\n");
1411         rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1412                                        compdata + compstr->dwResultStrOffset,
1413                                        lpBuf, dwBufLen, unicode);
1414         break;
1415     case GCS_RESULTREADSTR:
1416         TRACE("GCS_RESULTREADSTR\n");
1417         rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1418         break;
1419     case GCS_RESULTREADCLAUSE:
1420         TRACE("GCS_RESULTREADCLAUSE\n");
1421         rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1422                                        compdata + compstr->dwResultStrOffset,
1423                                        lpBuf, dwBufLen, unicode);
1424         break;
1425     case GCS_COMPREADSTR:
1426         TRACE("GCS_COMPREADSTR\n");
1427         rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1428         break;
1429     case GCS_COMPREADATTR:
1430         TRACE("GCS_COMPREADATTR\n");
1431         rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1432                                      compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1433                                      lpBuf, dwBufLen, unicode);
1434         break;
1435     case GCS_COMPREADCLAUSE:
1436         TRACE("GCS_COMPREADCLAUSE\n");
1437         rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1438                                        compdata + compstr->dwCompStrOffset,
1439                                        lpBuf, dwBufLen, unicode);
1440         break;
1441     case GCS_CURSORPOS:
1442         TRACE("GCS_CURSORPOS\n");
1443         rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1444         break;
1445     case GCS_DELTASTART:
1446         TRACE("GCS_DELTASTART\n");
1447         rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1448         break;
1449     default:
1450         FIXME("Unhandled index 0x%x\n",dwIndex);
1451         break;
1452     }
1453 
1454     ImmUnlockIMCC(data->IMC.hCompStr);
1455 
1456     return rc;
1457 }
1458 
1459 /***********************************************************************
1460  *		ImmGetCompositionStringA (IMM32.@)
1461  */
1462 LONG WINAPI ImmGetCompositionStringA(
1463   HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1464 {
1465     return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1466 }
1467 
1468 
1469 /***********************************************************************
1470  *		ImmGetCompositionStringW (IMM32.@)
1471  */
1472 LONG WINAPI ImmGetCompositionStringW(
1473   HIMC hIMC, DWORD dwIndex,
1474   LPVOID lpBuf, DWORD dwBufLen)
1475 {
1476     return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1477 }
1478 
1479 /***********************************************************************
1480  *		ImmGetCompositionWindow (IMM32.@)
1481  */
1482 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1483 {
1484     InputContextData *data = get_imc_data(hIMC);
1485 
1486     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1487 
1488     if (!data)
1489         return FALSE;
1490 
1491     *lpCompForm = data->IMC.cfCompForm;
1492     return TRUE;
1493 }
1494 
1495 /***********************************************************************
1496  *		ImmGetContext (IMM32.@)
1497  *
1498  */
1499 HIMC WINAPI ImmGetContext(HWND hWnd)
1500 {
1501     HIMC rc;
1502 
1503     TRACE("%p\n", hWnd);
1504 
1505     if (!IsWindow(hWnd))
1506     {
1507         SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1508         return NULL;
1509     }
1510 
1511     rc = GetPropW(hWnd,szwWineIMCProperty);
1512     if (rc == (HIMC)-1)
1513         rc = NULL;
1514     else if (rc == NULL)
1515         rc = get_default_context( hWnd );
1516 
1517     if (rc)
1518     {
1519         InputContextData *data = rc;
1520         data->IMC.hWnd = hWnd;
1521     }
1522 
1523     TRACE("returning %p\n", rc);
1524 
1525     return rc;
1526 }
1527 
1528 /***********************************************************************
1529  *		ImmGetConversionListA (IMM32.@)
1530  */
1531 DWORD WINAPI ImmGetConversionListA(
1532   HKL hKL, HIMC hIMC,
1533   LPCSTR pSrc, LPCANDIDATELIST lpDst,
1534   DWORD dwBufLen, UINT uFlag)
1535 {
1536     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1537     TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
1538                 dwBufLen, uFlag);
1539     if (immHkl->hIME && immHkl->pImeConversionList)
1540     {
1541         if (!is_kbd_ime_unicode(immHkl))
1542             return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
1543         else
1544         {
1545             LPCANDIDATELIST lpwDst;
1546             DWORD ret = 0, len;
1547             LPWSTR pwSrc = strdupAtoW(pSrc);
1548 
1549             len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
1550             lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
1551             if ( lpwDst )
1552             {
1553                 immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
1554                 ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
1555                 HeapFree(GetProcessHeap(), 0, lpwDst);
1556             }
1557             HeapFree(GetProcessHeap(), 0, pwSrc);
1558 
1559             return ret;
1560         }
1561     }
1562     else
1563         return 0;
1564 }
1565 
1566 /***********************************************************************
1567  *		ImmGetConversionListW (IMM32.@)
1568  */
1569 DWORD WINAPI ImmGetConversionListW(
1570   HKL hKL, HIMC hIMC,
1571   LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1572   DWORD dwBufLen, UINT uFlag)
1573 {
1574     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1575     TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
1576                 dwBufLen, uFlag);
1577     if (immHkl->hIME && immHkl->pImeConversionList)
1578     {
1579         if (is_kbd_ime_unicode(immHkl))
1580             return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
1581         else
1582         {
1583             LPCANDIDATELIST lpaDst;
1584             DWORD ret = 0, len;
1585             LPSTR paSrc = strdupWtoA(pSrc);
1586 
1587             len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
1588             lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
1589             if ( lpaDst )
1590             {
1591                 immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
1592                 ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
1593                 HeapFree(GetProcessHeap(), 0, lpaDst);
1594             }
1595             HeapFree(GetProcessHeap(), 0, paSrc);
1596 
1597             return ret;
1598         }
1599     }
1600     else
1601         return 0;
1602 }
1603 
1604 /***********************************************************************
1605  *		ImmGetConversionStatus (IMM32.@)
1606  */
1607 BOOL WINAPI ImmGetConversionStatus(
1608   HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1609 {
1610     InputContextData *data = get_imc_data(hIMC);
1611 
1612     TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1613 
1614     if (!data)
1615         return FALSE;
1616 
1617     if (lpfdwConversion)
1618         *lpfdwConversion = data->IMC.fdwConversion;
1619     if (lpfdwSentence)
1620         *lpfdwSentence = data->IMC.fdwSentence;
1621 
1622     return TRUE;
1623 }
1624 
1625 static BOOL needs_ime_window(HWND hwnd)
1626 {
1627     WCHAR classW[8];
1628 
1629     if (GetClassNameW(hwnd, classW, sizeof(classW)/sizeof(classW[0])) &&
1630         !strcmpW(classW, szwIME))
1631         return FALSE;
1632     if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
1633 
1634     return TRUE;
1635 }
1636 
1637 /***********************************************************************
1638  *		__wine_register_window (IMM32.@)
1639  */
1640 BOOL WINAPI __wine_register_window(HWND hwnd)
1641 {
1642     HWND new = NULL;
1643     IMMThreadData *thread_data;
1644     TRACE("(%p)\n", hwnd);
1645 
1646     if (!needs_ime_window(hwnd))
1647         return FALSE;
1648 
1649     thread_data = IMM_GetThreadData(hwnd, 0);
1650     if (!thread_data)
1651         return FALSE;
1652 
1653     if (thread_data->disableIME || disable_ime)
1654     {
1655         TRACE("IME for this thread is disabled\n");
1656         LeaveCriticalSection(&threaddata_cs);
1657         return FALSE;
1658     }
1659     thread_data->windowRefs++;
1660     TRACE("windowRefs=%u, hwndDefault=%p\n",
1661           thread_data->windowRefs, thread_data->hwndDefault);
1662 
1663     /* Create default IME window */
1664     if (thread_data->windowRefs == 1)
1665     {
1666         /* Do not create the window inside of a critical section */
1667         LeaveCriticalSection(&threaddata_cs);
1668         new = CreateWindowExW( 0, szwIME, szwDefaultIME,
1669                                WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
1670                                0, 0, 1, 1, 0, 0, 0, 0);
1671         /* thread_data is in the current thread so we can assume it's still valid */
1672         EnterCriticalSection(&threaddata_cs);
1673         /* See if anyone beat us */
1674         if (thread_data->hwndDefault == NULL)
1675         {
1676             thread_data->hwndDefault = new;
1677             new = NULL;
1678             TRACE("Default is %p\n", thread_data->hwndDefault);
1679         }
1680     }
1681 
1682     LeaveCriticalSection(&threaddata_cs);
1683 
1684     /* Clean up an unused new window outside of the critical section */
1685     if (new != NULL)
1686         DestroyWindow(new);
1687     return TRUE;
1688 }
1689 
1690 /***********************************************************************
1691  *		__wine_unregister_window (IMM32.@)
1692  */
1693 void WINAPI __wine_unregister_window(HWND hwnd)
1694 {
1695     HWND to_destroy = 0;
1696     IMMThreadData *thread_data;
1697     TRACE("(%p)\n", hwnd);
1698 
1699     thread_data = IMM_GetThreadData(hwnd, 0);
1700     if (!thread_data) return;
1701 
1702     thread_data->windowRefs--;
1703     TRACE("windowRefs=%u, hwndDefault=%p\n",
1704           thread_data->windowRefs, thread_data->hwndDefault);
1705 
1706     /* Destroy default IME window */
1707     if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
1708     {
1709         to_destroy = thread_data->hwndDefault;
1710         thread_data->hwndDefault = NULL;
1711     }
1712     LeaveCriticalSection(&threaddata_cs);
1713 
1714     if (to_destroy) DestroyWindow( to_destroy );
1715 }
1716 
1717 /***********************************************************************
1718  *		ImmGetDefaultIMEWnd (IMM32.@)
1719  */
1720 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1721 {
1722     HWND ret;
1723     IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
1724     if (!thread_data)
1725         return NULL;
1726     ret = thread_data->hwndDefault;
1727     LeaveCriticalSection(&threaddata_cs);
1728     TRACE("Default is %p\n",ret);
1729     return ret;
1730 }
1731 
1732 /***********************************************************************
1733  *		ImmGetDescriptionA (IMM32.@)
1734  */
1735 UINT WINAPI ImmGetDescriptionA(
1736   HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1737 {
1738   WCHAR *buf;
1739   DWORD len;
1740 
1741   TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1742 
1743   /* find out how many characters in the unicode buffer */
1744   len = ImmGetDescriptionW( hKL, NULL, 0 );
1745   if (!len)
1746     return 0;
1747 
1748   /* allocate a buffer of that size */
1749   buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1750   if( !buf )
1751   return 0;
1752 
1753   /* fetch the unicode buffer */
1754   len = ImmGetDescriptionW( hKL, buf, len + 1 );
1755 
1756   /* convert it back to ASCII */
1757   len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1758                              lpszDescription, uBufLen, NULL, NULL );
1759 
1760   HeapFree( GetProcessHeap(), 0, buf );
1761 
1762   if (len == 0)
1763     return 0;
1764 
1765   return len - 1;
1766 }
1767 
1768 /***********************************************************************
1769  *		ImmGetDescriptionW (IMM32.@)
1770  */
1771 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1772 {
1773   static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 };
1774 
1775   FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1776 
1777   if (!hKL) return 0;
1778   if (!uBufLen) return lstrlenW( name );
1779   lstrcpynW( lpszDescription, name, uBufLen );
1780   return lstrlenW( lpszDescription );
1781 }
1782 
1783 /***********************************************************************
1784  *		ImmGetGuideLineA (IMM32.@)
1785  */
1786 DWORD WINAPI ImmGetGuideLineA(
1787   HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1788 {
1789   FIXME("(%p, %d, %s, %d): stub\n",
1790     hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1791   );
1792   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1793   return 0;
1794 }
1795 
1796 /***********************************************************************
1797  *		ImmGetGuideLineW (IMM32.@)
1798  */
1799 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1800 {
1801   FIXME("(%p, %d, %s, %d): stub\n",
1802     hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1803   );
1804   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1805   return 0;
1806 }
1807 
1808 /***********************************************************************
1809  *		ImmGetIMEFileNameA (IMM32.@)
1810  */
1811 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1812 {
1813     LPWSTR bufW = NULL;
1814     UINT wBufLen = uBufLen;
1815     UINT rc;
1816 
1817     if (uBufLen && lpszFileName)
1818         bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1819     else /* We need this to get the number of byte required */
1820     {
1821         bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1822         wBufLen = MAX_PATH;
1823     }
1824 
1825     rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1826 
1827     if (rc > 0)
1828     {
1829         if (uBufLen && lpszFileName)
1830             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1831                                  uBufLen, NULL, NULL);
1832         else /* get the length */
1833             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1834                                      NULL);
1835     }
1836 
1837     HeapFree(GetProcessHeap(),0,bufW);
1838     return rc;
1839 }
1840 
1841 /***********************************************************************
1842  *		ImmGetIMEFileNameW (IMM32.@)
1843  */
1844 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1845 {
1846     HKEY hkey;
1847     DWORD length;
1848     DWORD rc;
1849     WCHAR regKey[sizeof(szImeRegFmt)/sizeof(WCHAR)+8];
1850 
1851     wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
1852     rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1853     if (rc != ERROR_SUCCESS)
1854     {
1855         SetLastError(rc);
1856         return 0;
1857     }
1858 
1859     length = 0;
1860     rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length);
1861 
1862     if (rc != ERROR_SUCCESS)
1863     {
1864         RegCloseKey(hkey);
1865         SetLastError(rc);
1866         return 0;
1867     }
1868     if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1869     {
1870         RegCloseKey(hkey);
1871         if (lpszFileName)
1872         {
1873             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1874             return 0;
1875         }
1876         else
1877             return length / sizeof(WCHAR);
1878     }
1879 
1880     RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1881 
1882     RegCloseKey(hkey);
1883 
1884     return length / sizeof(WCHAR);
1885 }
1886 
1887 /***********************************************************************
1888  *		ImmGetOpenStatus (IMM32.@)
1889  */
1890 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1891 {
1892   InputContextData *data = get_imc_data(hIMC);
1893   static int i;
1894 
1895     if (!data)
1896         return FALSE;
1897 
1898     TRACE("(%p): semi-stub\n", hIMC);
1899 
1900     if (!i++)
1901       FIXME("(%p): semi-stub\n", hIMC);
1902 
1903   return data->IMC.fOpen;
1904 }
1905 
1906 /***********************************************************************
1907  *		ImmGetProperty (IMM32.@)
1908  */
1909 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1910 {
1911     DWORD rc = 0;
1912     ImmHkl *kbd;
1913 
1914     TRACE("(%p, %d)\n", hKL, fdwIndex);
1915     kbd = IMM_GetImmHkl(hKL);
1916 
1917     if (kbd && kbd->hIME)
1918     {
1919         switch (fdwIndex)
1920         {
1921             case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
1922             case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
1923             case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
1924             case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
1925             case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
1926             case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
1927             case IGP_UI: rc = 0; break;
1928             default: rc = 0;
1929         }
1930     }
1931     return rc;
1932 }
1933 
1934 /***********************************************************************
1935  *		ImmGetRegisterWordStyleA (IMM32.@)
1936  */
1937 UINT WINAPI ImmGetRegisterWordStyleA(
1938   HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1939 {
1940     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1941     TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1942     if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1943     {
1944         if (!is_kbd_ime_unicode(immHkl))
1945             return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
1946         else
1947         {
1948             STYLEBUFW sbw;
1949             UINT rc;
1950 
1951             rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
1952             WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
1953                 lpStyleBuf->szDescription, 32, NULL, NULL);
1954             lpStyleBuf->dwStyle = sbw.dwStyle;
1955             return rc;
1956         }
1957     }
1958     else
1959         return 0;
1960 }
1961 
1962 /***********************************************************************
1963  *		ImmGetRegisterWordStyleW (IMM32.@)
1964  */
1965 UINT WINAPI ImmGetRegisterWordStyleW(
1966   HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1967 {
1968     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1969     TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1970     if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1971     {
1972         if (is_kbd_ime_unicode(immHkl))
1973             return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
1974         else
1975         {
1976             STYLEBUFA sba;
1977             UINT rc;
1978 
1979             rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
1980             MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
1981                 lpStyleBuf->szDescription, 32);
1982             lpStyleBuf->dwStyle = sba.dwStyle;
1983             return rc;
1984         }
1985     }
1986     else
1987         return 0;
1988 }
1989 
1990 /***********************************************************************
1991  *		ImmGetStatusWindowPos (IMM32.@)
1992  */
1993 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1994 {
1995     InputContextData *data = get_imc_data(hIMC);
1996 
1997     TRACE("(%p, %p)\n", hIMC, lpptPos);
1998 
1999     if (!data || !lpptPos)
2000         return FALSE;
2001 
2002     *lpptPos = data->IMC.ptStatusWndPos;
2003 
2004     return TRUE;
2005 }
2006 
2007 /***********************************************************************
2008  *		ImmGetVirtualKey (IMM32.@)
2009  */
2010 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
2011 {
2012   OSVERSIONINFOA version;
2013   InputContextData *data = ImmGetContext( hWnd );
2014   TRACE("%p\n", hWnd);
2015 
2016   if ( data )
2017       return data->lastVK;
2018 
2019   version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2020   GetVersionExA( &version );
2021   switch(version.dwPlatformId)
2022   {
2023   case VER_PLATFORM_WIN32_WINDOWS:
2024       return VK_PROCESSKEY;
2025   case VER_PLATFORM_WIN32_NT:
2026       return 0;
2027   default:
2028       FIXME("%d not supported\n",version.dwPlatformId);
2029       return VK_PROCESSKEY;
2030   }
2031 }
2032 
2033 /***********************************************************************
2034  *		ImmInstallIMEA (IMM32.@)
2035  */
2036 HKL WINAPI ImmInstallIMEA(
2037   LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
2038 {
2039     LPWSTR lpszwIMEFileName;
2040     LPWSTR lpszwLayoutText;
2041     HKL hkl;
2042 
2043     TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
2044                          debugstr_a(lpszLayoutText));
2045 
2046     lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
2047     lpszwLayoutText = strdupAtoW(lpszLayoutText);
2048 
2049     hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
2050 
2051     HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
2052     HeapFree(GetProcessHeap(),0,lpszwLayoutText);
2053     return hkl;
2054 }
2055 
2056 /***********************************************************************
2057  *		ImmInstallIMEW (IMM32.@)
2058  */
2059 HKL WINAPI ImmInstallIMEW(
2060   LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
2061 {
2062     INT lcid = GetUserDefaultLCID();
2063     INT count;
2064     HKL hkl;
2065     DWORD rc;
2066     HKEY hkey;
2067     WCHAR regKey[sizeof(szImeRegFmt)/sizeof(WCHAR)+8];
2068 
2069     TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
2070                           debugstr_w(lpszLayoutText));
2071 
2072     /* Start with 2.  e001 will be blank and so default to the wine internal IME */
2073     count = 2;
2074 
2075     while (count < 0xfff)
2076     {
2077         DWORD disposition = 0;
2078 
2079         hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
2080         wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
2081 
2082         rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
2083         if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
2084             break;
2085         else if (rc == ERROR_SUCCESS)
2086             RegCloseKey(hkey);
2087 
2088         count++;
2089     }
2090 
2091     if (count == 0xfff)
2092     {
2093         WARN("Unable to find slot to install IME\n");
2094         return 0;
2095     }
2096 
2097     if (rc == ERROR_SUCCESS)
2098     {
2099         rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
2100                             (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
2101         if (rc == ERROR_SUCCESS)
2102             rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
2103                                 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
2104         RegCloseKey(hkey);
2105         return hkl;
2106     }
2107     else
2108     {
2109         WARN("Unable to set IME registry values\n");
2110         return 0;
2111     }
2112 }
2113 
2114 /***********************************************************************
2115  *		ImmIsIME (IMM32.@)
2116  */
2117 BOOL WINAPI ImmIsIME(HKL hKL)
2118 {
2119     ImmHkl *ptr;
2120     TRACE("(%p):\n", hKL);
2121     ptr = IMM_GetImmHkl(hKL);
2122     return (ptr && ptr->hIME);
2123 }
2124 
2125 /***********************************************************************
2126  *		ImmIsUIMessageA (IMM32.@)
2127  */
2128 BOOL WINAPI ImmIsUIMessageA(
2129   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2130 {
2131     TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2132     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2133             (msg == WM_IME_SETCONTEXT) ||
2134             (msg == WM_IME_NOTIFY) ||
2135             (msg == WM_IME_COMPOSITIONFULL) ||
2136             (msg == WM_IME_SELECT) ||
2137             (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2138     {
2139         if (hWndIME)
2140             SendMessageA(hWndIME, msg, wParam, lParam);
2141 
2142         return TRUE;
2143     }
2144     return FALSE;
2145 }
2146 
2147 /***********************************************************************
2148  *		ImmIsUIMessageW (IMM32.@)
2149  */
2150 BOOL WINAPI ImmIsUIMessageW(
2151   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2152 {
2153     TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2154     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2155             (msg == WM_IME_SETCONTEXT) ||
2156             (msg == WM_IME_NOTIFY) ||
2157             (msg == WM_IME_COMPOSITIONFULL) ||
2158             (msg == WM_IME_SELECT) ||
2159             (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2160     {
2161         if (hWndIME)
2162             SendMessageW(hWndIME, msg, wParam, lParam);
2163 
2164         return TRUE;
2165     }
2166     return FALSE;
2167 }
2168 
2169 /***********************************************************************
2170  *		ImmNotifyIME (IMM32.@)
2171  */
2172 BOOL WINAPI ImmNotifyIME(
2173   HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2174 {
2175     InputContextData *data = get_imc_data(hIMC);
2176 
2177     TRACE("(%p, %d, %d, %d)\n",
2178         hIMC, dwAction, dwIndex, dwValue);
2179 
2180     if (hIMC == NULL)
2181     {
2182         SetLastError(ERROR_SUCCESS);
2183         return FALSE;
2184     }
2185 
2186     if (!data || ! data->immKbd->pNotifyIME)
2187     {
2188         return FALSE;
2189     }
2190 
2191     return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
2192 }
2193 
2194 /***********************************************************************
2195  *		ImmRegisterWordA (IMM32.@)
2196  */
2197 BOOL WINAPI ImmRegisterWordA(
2198   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
2199 {
2200     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2201     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2202                     debugstr_a(lpszRegister));
2203     if (immHkl->hIME && immHkl->pImeRegisterWord)
2204     {
2205         if (!is_kbd_ime_unicode(immHkl))
2206             return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
2207                                             (LPCWSTR)lpszRegister);
2208         else
2209         {
2210             LPWSTR lpszwReading = strdupAtoW(lpszReading);
2211             LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
2212             BOOL rc;
2213 
2214             rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
2215             HeapFree(GetProcessHeap(),0,lpszwReading);
2216             HeapFree(GetProcessHeap(),0,lpszwRegister);
2217             return rc;
2218         }
2219     }
2220     else
2221         return FALSE;
2222 }
2223 
2224 /***********************************************************************
2225  *		ImmRegisterWordW (IMM32.@)
2226  */
2227 BOOL WINAPI ImmRegisterWordW(
2228   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
2229 {
2230     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2231     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2232                     debugstr_w(lpszRegister));
2233     if (immHkl->hIME && immHkl->pImeRegisterWord)
2234     {
2235         if (is_kbd_ime_unicode(immHkl))
2236             return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
2237         else
2238         {
2239             LPSTR lpszaReading = strdupWtoA(lpszReading);
2240             LPSTR lpszaRegister = strdupWtoA(lpszRegister);
2241             BOOL rc;
2242 
2243             rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
2244                                           (LPCWSTR)lpszaRegister);
2245             HeapFree(GetProcessHeap(),0,lpszaReading);
2246             HeapFree(GetProcessHeap(),0,lpszaRegister);
2247             return rc;
2248         }
2249     }
2250     else
2251         return FALSE;
2252 }
2253 
2254 /***********************************************************************
2255  *		ImmReleaseContext (IMM32.@)
2256  */
2257 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2258 {
2259   static BOOL shown = FALSE;
2260 
2261   if (!shown) {
2262      FIXME("(%p, %p): stub\n", hWnd, hIMC);
2263      shown = TRUE;
2264   }
2265   return TRUE;
2266 }
2267 
2268 /***********************************************************************
2269 *              ImmRequestMessageA(IMM32.@)
2270 */
2271 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2272 {
2273     InputContextData *data = get_imc_data(hIMC);
2274 
2275     TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2276 
2277     if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2278 
2279     SetLastError(ERROR_INVALID_HANDLE);
2280     return 0;
2281 }
2282 
2283 /***********************************************************************
2284 *              ImmRequestMessageW(IMM32.@)
2285 */
2286 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2287 {
2288     InputContextData *data = get_imc_data(hIMC);
2289 
2290     TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2291 
2292     if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2293 
2294     SetLastError(ERROR_INVALID_HANDLE);
2295     return 0;
2296 }
2297 
2298 /***********************************************************************
2299  *		ImmSetCandidateWindow (IMM32.@)
2300  */
2301 BOOL WINAPI ImmSetCandidateWindow(
2302   HIMC hIMC, LPCANDIDATEFORM lpCandidate)
2303 {
2304     InputContextData *data = get_imc_data(hIMC);
2305 
2306     TRACE("(%p, %p)\n", hIMC, lpCandidate);
2307 
2308     if (!data || !lpCandidate)
2309         return FALSE;
2310 
2311     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2312         return FALSE;
2313 
2314     TRACE("\t%x, %x, %s, %s\n",
2315           lpCandidate->dwIndex, lpCandidate->dwStyle,
2316           wine_dbgstr_point(&lpCandidate->ptCurrentPos),
2317           wine_dbgstr_rect(&lpCandidate->rcArea));
2318 
2319     if ( lpCandidate->dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) )
2320         return FALSE;
2321 
2322     data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
2323     ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
2324     ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
2325 
2326     return TRUE;
2327 }
2328 
2329 /***********************************************************************
2330  *		ImmSetCompositionFontA (IMM32.@)
2331  */
2332 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
2333 {
2334     InputContextData *data = get_imc_data(hIMC);
2335     TRACE("(%p, %p)\n", hIMC, lplf);
2336 
2337     if (!data || !lplf)
2338     {
2339         SetLastError(ERROR_INVALID_HANDLE);
2340         return FALSE;
2341     }
2342 
2343     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2344         return FALSE;
2345 
2346     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
2347     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
2348                         LF_FACESIZE);
2349     ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2350     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2351 
2352     return TRUE;
2353 }
2354 
2355 /***********************************************************************
2356  *		ImmSetCompositionFontW (IMM32.@)
2357  */
2358 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
2359 {
2360     InputContextData *data = get_imc_data(hIMC);
2361     TRACE("(%p, %p)\n", hIMC, lplf);
2362 
2363     if (!data || !lplf)
2364     {
2365         SetLastError(ERROR_INVALID_HANDLE);
2366         return FALSE;
2367     }
2368 
2369     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2370         return FALSE;
2371 
2372     data->IMC.lfFont.W = *lplf;
2373     ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2374     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2375 
2376     return TRUE;
2377 }
2378 
2379 /***********************************************************************
2380  *		ImmSetCompositionStringA (IMM32.@)
2381  */
2382 BOOL WINAPI ImmSetCompositionStringA(
2383   HIMC hIMC, DWORD dwIndex,
2384   LPCVOID lpComp, DWORD dwCompLen,
2385   LPCVOID lpRead, DWORD dwReadLen)
2386 {
2387     DWORD comp_len;
2388     DWORD read_len;
2389     WCHAR *CompBuffer = NULL;
2390     WCHAR *ReadBuffer = NULL;
2391     BOOL rc;
2392     InputContextData *data = get_imc_data(hIMC);
2393 
2394     TRACE("(%p, %d, %p, %d, %p, %d):\n",
2395             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2396 
2397     if (!data)
2398         return FALSE;
2399 
2400     if (!(dwIndex == SCS_SETSTR ||
2401           dwIndex == SCS_CHANGEATTR ||
2402           dwIndex == SCS_CHANGECLAUSE ||
2403           dwIndex == SCS_SETRECONVERTSTRING ||
2404           dwIndex == SCS_QUERYRECONVERTSTRING))
2405         return FALSE;
2406 
2407     if (!is_himc_ime_unicode(data))
2408         return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2409                         dwCompLen, lpRead, dwReadLen);
2410 
2411     comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2412     if (comp_len)
2413     {
2414         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2415         MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2416     }
2417 
2418     read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2419     if (read_len)
2420     {
2421         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2422         MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2423     }
2424 
2425     rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2426                                    ReadBuffer, read_len);
2427 
2428     HeapFree(GetProcessHeap(), 0, CompBuffer);
2429     HeapFree(GetProcessHeap(), 0, ReadBuffer);
2430 
2431     return rc;
2432 }
2433 
2434 /***********************************************************************
2435  *		ImmSetCompositionStringW (IMM32.@)
2436  */
2437 BOOL WINAPI ImmSetCompositionStringW(
2438 	HIMC hIMC, DWORD dwIndex,
2439 	LPCVOID lpComp, DWORD dwCompLen,
2440 	LPCVOID lpRead, DWORD dwReadLen)
2441 {
2442     DWORD comp_len;
2443     DWORD read_len;
2444     CHAR *CompBuffer = NULL;
2445     CHAR *ReadBuffer = NULL;
2446     BOOL rc;
2447     InputContextData *data = get_imc_data(hIMC);
2448 
2449     TRACE("(%p, %d, %p, %d, %p, %d):\n",
2450             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2451 
2452     if (!data)
2453         return FALSE;
2454 
2455     if (!(dwIndex == SCS_SETSTR ||
2456           dwIndex == SCS_CHANGEATTR ||
2457           dwIndex == SCS_CHANGECLAUSE ||
2458           dwIndex == SCS_SETRECONVERTSTRING ||
2459           dwIndex == SCS_QUERYRECONVERTSTRING))
2460         return FALSE;
2461 
2462     if (is_himc_ime_unicode(data))
2463         return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2464                         dwCompLen, lpRead, dwReadLen);
2465 
2466     comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2467                                    NULL);
2468     if (comp_len)
2469     {
2470         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
2471         WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2472                             NULL, NULL);
2473     }
2474 
2475     read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2476                                    NULL);
2477     if (read_len)
2478     {
2479         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
2480         WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2481                             NULL, NULL);
2482     }
2483 
2484     rc =  ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2485                                    ReadBuffer, read_len);
2486 
2487     HeapFree(GetProcessHeap(), 0, CompBuffer);
2488     HeapFree(GetProcessHeap(), 0, ReadBuffer);
2489 
2490     return rc;
2491 }
2492 
2493 /***********************************************************************
2494  *		ImmSetCompositionWindow (IMM32.@)
2495  */
2496 BOOL WINAPI ImmSetCompositionWindow(
2497   HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2498 {
2499     BOOL reshow = FALSE;
2500     InputContextData *data = get_imc_data(hIMC);
2501 
2502     TRACE("(%p, %p)\n", hIMC, lpCompForm);
2503     if (lpCompForm)
2504         TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle,
2505               wine_dbgstr_point(&lpCompForm->ptCurrentPos),
2506               wine_dbgstr_rect(&lpCompForm->rcArea));
2507 
2508     if (!data)
2509     {
2510         SetLastError(ERROR_INVALID_HANDLE);
2511         return FALSE;
2512     }
2513 
2514     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2515         return FALSE;
2516 
2517     data->IMC.cfCompForm = *lpCompForm;
2518 
2519     if (IsWindowVisible(data->immKbd->UIWnd))
2520     {
2521         reshow = TRUE;
2522         ShowWindow(data->immKbd->UIWnd,SW_HIDE);
2523     }
2524 
2525     /* FIXME: this is a partial stub */
2526 
2527     if (reshow)
2528         ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
2529 
2530     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2531     return TRUE;
2532 }
2533 
2534 /***********************************************************************
2535  *		ImmSetConversionStatus (IMM32.@)
2536  */
2537 BOOL WINAPI ImmSetConversionStatus(
2538   HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2539 {
2540     DWORD oldConversion, oldSentence;
2541     InputContextData *data = get_imc_data(hIMC);
2542 
2543     TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
2544 
2545     if (!data)
2546     {
2547         SetLastError(ERROR_INVALID_HANDLE);
2548         return FALSE;
2549     }
2550 
2551     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2552         return FALSE;
2553 
2554     if ( fdwConversion != data->IMC.fdwConversion )
2555     {
2556         oldConversion = data->IMC.fdwConversion;
2557         data->IMC.fdwConversion = fdwConversion;
2558         ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
2559         ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
2560     }
2561     if ( fdwSentence != data->IMC.fdwSentence )
2562     {
2563         oldSentence = data->IMC.fdwSentence;
2564         data->IMC.fdwSentence = fdwSentence;
2565         ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
2566         ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
2567     }
2568 
2569     return TRUE;
2570 }
2571 
2572 /***********************************************************************
2573  *		ImmSetOpenStatus (IMM32.@)
2574  */
2575 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2576 {
2577     InputContextData *data = get_imc_data(hIMC);
2578 
2579     TRACE("%p %d\n", hIMC, fOpen);
2580 
2581     if (!data)
2582     {
2583         SetLastError(ERROR_INVALID_HANDLE);
2584         return FALSE;
2585     }
2586 
2587     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2588         return FALSE;
2589 
2590     if (data->immKbd->UIWnd == NULL)
2591     {
2592         /* create the ime window */
2593         data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
2594                     data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
2595                     0, data->immKbd->hIME, 0);
2596         SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2597     }
2598     else if (fOpen)
2599         SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2600 
2601     if (!fOpen != !data->IMC.fOpen)
2602     {
2603         data->IMC.fOpen = fOpen;
2604         ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
2605         ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
2606     }
2607 
2608     return TRUE;
2609 }
2610 
2611 /***********************************************************************
2612  *		ImmSetStatusWindowPos (IMM32.@)
2613  */
2614 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2615 {
2616     InputContextData *data = get_imc_data(hIMC);
2617 
2618     TRACE("(%p, %p)\n", hIMC, lpptPos);
2619 
2620     if (!data || !lpptPos)
2621     {
2622         SetLastError(ERROR_INVALID_HANDLE);
2623         return FALSE;
2624     }
2625 
2626     if (IMM_IsCrossThreadAccess(NULL, hIMC))
2627         return FALSE;
2628 
2629     TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
2630 
2631     data->IMC.ptStatusWndPos = *lpptPos;
2632     ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
2633     ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
2634 
2635     return TRUE;
2636 }
2637 
2638 /***********************************************************************
2639  *              ImmCreateSoftKeyboard(IMM32.@)
2640  */
2641 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2642 {
2643     FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2644     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2645     return 0;
2646 }
2647 
2648 /***********************************************************************
2649  *              ImmDestroySoftKeyboard(IMM32.@)
2650  */
2651 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2652 {
2653     FIXME("(%p): stub\n", hSoftWnd);
2654     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2655     return FALSE;
2656 }
2657 
2658 /***********************************************************************
2659  *              ImmShowSoftKeyboard(IMM32.@)
2660  */
2661 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2662 {
2663     FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2664     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2665     return FALSE;
2666 }
2667 
2668 /***********************************************************************
2669  *		ImmSimulateHotKey (IMM32.@)
2670  */
2671 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2672 {
2673   FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
2674   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2675   return FALSE;
2676 }
2677 
2678 /***********************************************************************
2679  *		ImmUnregisterWordA (IMM32.@)
2680  */
2681 BOOL WINAPI ImmUnregisterWordA(
2682   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2683 {
2684     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2685     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2686             debugstr_a(lpszUnregister));
2687     if (immHkl->hIME && immHkl->pImeUnregisterWord)
2688     {
2689         if (!is_kbd_ime_unicode(immHkl))
2690             return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
2691                                               (LPCWSTR)lpszUnregister);
2692         else
2693         {
2694             LPWSTR lpszwReading = strdupAtoW(lpszReading);
2695             LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
2696             BOOL rc;
2697 
2698             rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
2699             HeapFree(GetProcessHeap(),0,lpszwReading);
2700             HeapFree(GetProcessHeap(),0,lpszwUnregister);
2701             return rc;
2702         }
2703     }
2704     else
2705         return FALSE;
2706 }
2707 
2708 /***********************************************************************
2709  *		ImmUnregisterWordW (IMM32.@)
2710  */
2711 BOOL WINAPI ImmUnregisterWordW(
2712   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2713 {
2714     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2715     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2716             debugstr_w(lpszUnregister));
2717     if (immHkl->hIME && immHkl->pImeUnregisterWord)
2718     {
2719         if (is_kbd_ime_unicode(immHkl))
2720             return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
2721         else
2722         {
2723             LPSTR lpszaReading = strdupWtoA(lpszReading);
2724             LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
2725             BOOL rc;
2726 
2727             rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
2728                                             (LPCWSTR)lpszaUnregister);
2729             HeapFree(GetProcessHeap(),0,lpszaReading);
2730             HeapFree(GetProcessHeap(),0,lpszaUnregister);
2731             return rc;
2732         }
2733     }
2734     else
2735         return FALSE;
2736 }
2737 
2738 /***********************************************************************
2739  *		ImmGetImeMenuItemsA (IMM32.@)
2740  */
2741 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2742    LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2743     DWORD dwSize)
2744 {
2745     InputContextData *data = get_imc_data(hIMC);
2746     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2747         lpImeParentMenu, lpImeMenu, dwSize);
2748 
2749     if (!data)
2750     {
2751         SetLastError(ERROR_INVALID_HANDLE);
2752         return 0;
2753     }
2754 
2755     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2756     {
2757         if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2758             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2759                                 (IMEMENUITEMINFOW*)lpImeParentMenu,
2760                                 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2761         else
2762         {
2763             IMEMENUITEMINFOW lpImeParentMenuW;
2764             IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2765             DWORD rc;
2766 
2767             if (lpImeParentMenu)
2768                 parent = &lpImeParentMenuW;
2769             if (lpImeMenu)
2770             {
2771                 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2772                 dwSize = count * sizeof(IMEMENUITEMINFOW);
2773                 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2774             }
2775             else
2776                 lpImeMenuW = NULL;
2777 
2778             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2779                                 parent, lpImeMenuW, dwSize);
2780 
2781             if (lpImeParentMenu)
2782             {
2783                 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2784                 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2785                 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2786                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2787                     NULL, NULL);
2788             }
2789             if (lpImeMenu && rc)
2790             {
2791                 unsigned int i;
2792                 for (i = 0; i < rc; i++)
2793                 {
2794                     memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2795                     lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2796                     WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2797                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2798                         NULL, NULL);
2799                 }
2800             }
2801             HeapFree(GetProcessHeap(),0,lpImeMenuW);
2802             return rc;
2803         }
2804     }
2805     else
2806         return 0;
2807 }
2808 
2809 /***********************************************************************
2810 *		ImmGetImeMenuItemsW (IMM32.@)
2811 */
2812 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2813    LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2814    DWORD dwSize)
2815 {
2816     InputContextData *data = get_imc_data(hIMC);
2817     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2818         lpImeParentMenu, lpImeMenu, dwSize);
2819 
2820     if (!data)
2821     {
2822         SetLastError(ERROR_INVALID_HANDLE);
2823         return 0;
2824     }
2825 
2826     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2827     {
2828         if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2829             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2830                                 lpImeParentMenu, lpImeMenu, dwSize);
2831         else
2832         {
2833             IMEMENUITEMINFOA lpImeParentMenuA;
2834             IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2835             DWORD rc;
2836 
2837             if (lpImeParentMenu)
2838                 parent = &lpImeParentMenuA;
2839             if (lpImeMenu)
2840             {
2841                 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2842                 dwSize = count * sizeof(IMEMENUITEMINFOA);
2843                 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2844             }
2845             else
2846                 lpImeMenuA = NULL;
2847 
2848             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2849                                 (IMEMENUITEMINFOW*)parent,
2850                                 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2851 
2852             if (lpImeParentMenu)
2853             {
2854                 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2855                 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2856                 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2857                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2858             }
2859             if (lpImeMenu && rc)
2860             {
2861                 unsigned int i;
2862                 for (i = 0; i < rc; i++)
2863                 {
2864                     memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2865                     lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2866                     MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2867                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2868                 }
2869             }
2870             HeapFree(GetProcessHeap(),0,lpImeMenuA);
2871             return rc;
2872         }
2873     }
2874     else
2875         return 0;
2876 }
2877 
2878 /***********************************************************************
2879 *		ImmLockIMC(IMM32.@)
2880 */
2881 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2882 {
2883     InputContextData *data = get_imc_data(hIMC);
2884 
2885     if (!data)
2886         return NULL;
2887     data->dwLock++;
2888     return &data->IMC;
2889 }
2890 
2891 /***********************************************************************
2892 *		ImmUnlockIMC(IMM32.@)
2893 */
2894 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2895 {
2896     InputContextData *data = get_imc_data(hIMC);
2897 
2898     if (!data)
2899         return FALSE;
2900     if (data->dwLock)
2901         data->dwLock--;
2902     return TRUE;
2903 }
2904 
2905 /***********************************************************************
2906 *		ImmGetIMCLockCount(IMM32.@)
2907 */
2908 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2909 {
2910     InputContextData *data = get_imc_data(hIMC);
2911     if (!data)
2912         return 0;
2913     return data->dwLock;
2914 }
2915 
2916 /***********************************************************************
2917 *		ImmCreateIMCC(IMM32.@)
2918 */
2919 HIMCC  WINAPI ImmCreateIMCC(DWORD size)
2920 {
2921     return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
2922 }
2923 
2924 /***********************************************************************
2925 *       ImmDestroyIMCC(IMM32.@)
2926 */
2927 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2928 {
2929     return GlobalFree(block);
2930 }
2931 
2932 /***********************************************************************
2933 *		ImmLockIMCC(IMM32.@)
2934 */
2935 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2936 {
2937     return GlobalLock(imcc);
2938 }
2939 
2940 /***********************************************************************
2941 *		ImmUnlockIMCC(IMM32.@)
2942 */
2943 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2944 {
2945     return GlobalUnlock(imcc);
2946 }
2947 
2948 /***********************************************************************
2949 *		ImmGetIMCCLockCount(IMM32.@)
2950 */
2951 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2952 {
2953     return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
2954 }
2955 
2956 /***********************************************************************
2957 *		ImmReSizeIMCC(IMM32.@)
2958 */
2959 HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2960 {
2961     return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
2962 }
2963 
2964 /***********************************************************************
2965 *		ImmGetIMCCSize(IMM32.@)
2966 */
2967 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2968 {
2969     return GlobalSize(imcc);
2970 }
2971 
2972 /***********************************************************************
2973 *		ImmGenerateMessage(IMM32.@)
2974 */
2975 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2976 {
2977     InputContextData *data = get_imc_data(hIMC);
2978 
2979     if (!data)
2980     {
2981         SetLastError(ERROR_INVALID_HANDLE);
2982         return FALSE;
2983     }
2984 
2985     TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
2986     if (data->IMC.dwNumMsgBuf > 0)
2987     {
2988         LPTRANSMSG lpTransMsg;
2989         HIMCC hMsgBuf;
2990         DWORD i, dwNumMsgBuf;
2991 
2992         /* We are going to detach our hMsgBuff so that if processing messages
2993            generates new messages they go into a new buffer */
2994         hMsgBuf = data->IMC.hMsgBuf;
2995         dwNumMsgBuf = data->IMC.dwNumMsgBuf;
2996 
2997         data->IMC.hMsgBuf = ImmCreateIMCC(0);
2998         data->IMC.dwNumMsgBuf = 0;
2999 
3000         lpTransMsg = ImmLockIMCC(hMsgBuf);
3001         for (i = 0; i < dwNumMsgBuf; i++)
3002             ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
3003 
3004         ImmUnlockIMCC(hMsgBuf);
3005         ImmDestroyIMCC(hMsgBuf);
3006     }
3007 
3008     return TRUE;
3009 }
3010 
3011 /***********************************************************************
3012 *       ImmTranslateMessage(IMM32.@)
3013 *       ( Undocumented, call internally and from user32.dll )
3014 */
3015 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
3016 {
3017     InputContextData *data;
3018     HIMC imc = ImmGetContext(hwnd);
3019     BYTE state[256];
3020     UINT scancode;
3021     LPVOID list = 0;
3022     UINT msg_count;
3023     UINT uVirtKey;
3024     static const DWORD list_count = 10;
3025 
3026     TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
3027 
3028     if (imc)
3029         data = imc;
3030     else
3031         return FALSE;
3032 
3033     if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
3034         return FALSE;
3035 
3036     GetKeyboardState(state);
3037     scancode = lKeyData >> 0x10 & 0xff;
3038 
3039     list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
3040     ((DWORD*)list)[0] = list_count;
3041 
3042     if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3043     {
3044         WCHAR chr;
3045 
3046         if (!is_himc_ime_unicode(data))
3047             ToAscii(data->lastVK, scancode, state, &chr, 0);
3048         else
3049             ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
3050         uVirtKey = MAKELONG(data->lastVK,chr);
3051     }
3052     else
3053         uVirtKey = data->lastVK;
3054 
3055     msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
3056     TRACE("%i messages generated\n",msg_count);
3057     if (msg_count && msg_count <= list_count)
3058     {
3059         UINT i;
3060         LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
3061 
3062         for (i = 0; i < msg_count; i++)
3063             ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
3064     }
3065     else if (msg_count > list_count)
3066         ImmGenerateMessage(imc);
3067 
3068     HeapFree(GetProcessHeap(),0,list);
3069 
3070     data->lastVK = VK_PROCESSKEY;
3071 
3072     return (msg_count > 0);
3073 }
3074 
3075 /***********************************************************************
3076 *		ImmProcessKey(IMM32.@)
3077 *       ( Undocumented, called from user32.dll )
3078 */
3079 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
3080 {
3081     InputContextData *data;
3082     HIMC imc = ImmGetContext(hwnd);
3083     BYTE state[256];
3084 
3085     TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
3086 
3087     if (imc)
3088         data = imc;
3089     else
3090         return FALSE;
3091 
3092     /* Make sure we are inputting to the correct keyboard */
3093     if (data->immKbd->hkl != hKL)
3094     {
3095         ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
3096         if (new_hkl)
3097         {
3098             data->immKbd->pImeSelect(imc, FALSE);
3099             data->immKbd->uSelected--;
3100             data->immKbd = new_hkl;
3101             data->immKbd->pImeSelect(imc, TRUE);
3102             data->immKbd->uSelected++;
3103         }
3104         else
3105             return FALSE;
3106     }
3107 
3108     if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
3109         return FALSE;
3110 
3111     GetKeyboardState(state);
3112     if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
3113     {
3114         data->lastVK = vKey;
3115         return TRUE;
3116     }
3117 
3118     data->lastVK = VK_PROCESSKEY;
3119     return FALSE;
3120 }
3121 
3122 /***********************************************************************
3123 *		ImmDisableTextFrameService(IMM32.@)
3124 */
3125 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3126 {
3127     FIXME("Stub\n");
3128     return FALSE;
3129 }
3130 
3131 /***********************************************************************
3132  *              ImmEnumInputContext(IMM32.@)
3133  */
3134 
3135 BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
3136 {
3137     FIXME("Stub\n");
3138     return FALSE;
3139 }
3140 
3141 /***********************************************************************
3142  *              ImmGetHotKey(IMM32.@)
3143  */
3144 
3145 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
3146 {
3147     FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3148     return FALSE;
3149 }
3150