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