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