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