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