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