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