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