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