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