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