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