quartz: Fix discontinuities in wave parser.
[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  *              ImmSetCandidateWindow (IMM32.@)
1577  */
1578 BOOL WINAPI ImmSetCandidateWindow(
1579   HIMC hIMC, LPCANDIDATEFORM lpCandidate)
1580 {
1581   FIXME("(%p, %p): stub\n", hIMC, lpCandidate);
1582   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1583   return FALSE;
1584 }
1585
1586 /***********************************************************************
1587  *              ImmSetCompositionFontA (IMM32.@)
1588  */
1589 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1590 {
1591     InputContextData *data = (InputContextData*)hIMC;
1592     TRACE("(%p, %p)\n", hIMC, lplf);
1593
1594     if (!data)
1595         return FALSE;
1596
1597     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
1598     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
1599                         LF_FACESIZE);
1600     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1601
1602     return TRUE;
1603 }
1604
1605 /***********************************************************************
1606  *              ImmSetCompositionFontW (IMM32.@)
1607  */
1608 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1609 {
1610     InputContextData *data = (InputContextData*)hIMC;
1611     TRACE("(%p, %p)\n", hIMC, lplf);
1612
1613     if (!data)
1614         return FALSE;
1615
1616     data->IMC.lfFont.W = *lplf;
1617     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1618
1619     return TRUE;
1620 }
1621
1622 /***********************************************************************
1623  *              ImmSetCompositionStringA (IMM32.@)
1624  */
1625 BOOL WINAPI ImmSetCompositionStringA(
1626   HIMC hIMC, DWORD dwIndex,
1627   LPCVOID lpComp, DWORD dwCompLen,
1628   LPCVOID lpRead, DWORD dwReadLen)
1629 {
1630     DWORD comp_len;
1631     DWORD read_len;
1632     WCHAR *CompBuffer = NULL;
1633     WCHAR *ReadBuffer = NULL;
1634     BOOL rc;
1635     InputContextData *data = (InputContextData*)hIMC;
1636
1637     TRACE("(%p, %d, %p, %d, %p, %d):\n",
1638             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1639
1640     if (!data)
1641         return FALSE;
1642
1643     if (!is_himc_ime_unicode(data))
1644         return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1645                         dwCompLen, lpRead, dwReadLen);
1646
1647     comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
1648     if (comp_len)
1649     {
1650         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
1651         MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
1652     }
1653
1654     read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
1655     if (read_len)
1656     {
1657         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
1658         MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
1659     }
1660
1661     rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
1662                                    ReadBuffer, read_len);
1663
1664     HeapFree(GetProcessHeap(), 0, CompBuffer);
1665     HeapFree(GetProcessHeap(), 0, ReadBuffer);
1666
1667     return rc;
1668 }
1669
1670 /***********************************************************************
1671  *              ImmSetCompositionStringW (IMM32.@)
1672  */
1673 BOOL WINAPI ImmSetCompositionStringW(
1674         HIMC hIMC, DWORD dwIndex,
1675         LPCVOID lpComp, DWORD dwCompLen,
1676         LPCVOID lpRead, DWORD dwReadLen)
1677 {
1678     DWORD comp_len;
1679     DWORD read_len;
1680     CHAR *CompBuffer = NULL;
1681     CHAR *ReadBuffer = NULL;
1682     BOOL rc;
1683     InputContextData *data = (InputContextData*)hIMC;
1684
1685     TRACE("(%p, %d, %p, %d, %p, %d):\n",
1686             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1687
1688     if (!data)
1689         return FALSE;
1690
1691     if (is_himc_ime_unicode(data))
1692         return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1693                         dwCompLen, lpRead, dwReadLen);
1694
1695     comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
1696                                    NULL);
1697     if (comp_len)
1698     {
1699         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
1700         WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
1701                             NULL, NULL);
1702     }
1703
1704     read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
1705                                    NULL);
1706     if (read_len)
1707     {
1708         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
1709         WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
1710                             NULL, NULL);
1711     }
1712
1713     rc =  ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
1714                                    ReadBuffer, read_len);
1715
1716     HeapFree(GetProcessHeap(), 0, CompBuffer);
1717     HeapFree(GetProcessHeap(), 0, ReadBuffer);
1718
1719     return rc;
1720 }
1721
1722 /***********************************************************************
1723  *              ImmSetCompositionWindow (IMM32.@)
1724  */
1725 BOOL WINAPI ImmSetCompositionWindow(
1726   HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1727 {
1728     BOOL reshow = FALSE;
1729     InputContextData *data = (InputContextData*)hIMC;
1730
1731     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1732     TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
1733           lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top,
1734           lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right);
1735
1736     if (!data)
1737         return FALSE;
1738
1739     data->IMC.cfCompForm = *lpCompForm;
1740
1741     if (IsWindowVisible(IMM_GetThreadData()->hwndDefault))
1742     {
1743         reshow = TRUE;
1744         ShowWindow(IMM_GetThreadData()->hwndDefault,SW_HIDE);
1745     }
1746
1747     /* FIXME: this is a partial stub */
1748
1749     if (reshow)
1750         ShowWindow(IMM_GetThreadData()->hwndDefault,SW_SHOWNOACTIVATE);
1751
1752     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
1753     return TRUE;
1754 }
1755
1756 /***********************************************************************
1757  *              ImmSetConversionStatus (IMM32.@)
1758  */
1759 BOOL WINAPI ImmSetConversionStatus(
1760   HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1761 {
1762     InputContextData *data = (InputContextData*)hIMC;
1763
1764     TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
1765
1766     if (!data)
1767         return FALSE;
1768
1769     if ( fdwConversion != data->IMC.fdwConversion )
1770     {
1771         data->IMC.fdwConversion = fdwConversion;
1772         ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCONVERSIONMODE);
1773         ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
1774     }
1775     if ( fdwSentence != data->IMC.fdwSentence )
1776     {
1777         data->IMC.fdwSentence = fdwSentence;
1778         ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSENTENCEMODE);
1779         ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
1780     }
1781
1782     return TRUE;
1783 }
1784
1785 /***********************************************************************
1786  *              ImmSetOpenStatus (IMM32.@)
1787  */
1788 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
1789 {
1790     InputContextData *data = (InputContextData*)hIMC;
1791
1792     TRACE("%p %d\n", hIMC, fOpen);
1793
1794     if (!data)
1795         return FALSE;
1796
1797     if (data->imeWnd == NULL)
1798     {
1799         /* create the ime window */
1800         data->imeWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
1801                     data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
1802                     0, data->immKbd->hIME, 0);
1803         SetWindowLongW(data->imeWnd, IMMGWL_IMC, (LONG)data);
1804         IMM_GetThreadData()->hwndDefault = data->imeWnd;
1805     }
1806
1807     data->IMC.fOpen = fOpen;
1808     return ImmNotifyIME(hIMC,NI_CONTEXTUPDATED,0,IMC_SETOPENSTATUS);
1809 }
1810
1811 /***********************************************************************
1812  *              ImmSetStatusWindowPos (IMM32.@)
1813  */
1814 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1815 {
1816   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
1817   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1818   return FALSE;
1819 }
1820
1821 /***********************************************************************
1822  *              ImmSimulateHotKey (IMM32.@)
1823  */
1824 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
1825 {
1826   FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
1827   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1828   return FALSE;
1829 }
1830
1831 /***********************************************************************
1832  *              ImmUnregisterWordA (IMM32.@)
1833  */
1834 BOOL WINAPI ImmUnregisterWordA(
1835   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
1836 {
1837     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1838     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
1839             debugstr_a(lpszUnregister));
1840     if (immHkl->hIME && immHkl->pImeUnregisterWord)
1841     {
1842         if (!is_kbd_ime_unicode(immHkl))
1843             return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
1844                                               (LPCWSTR)lpszUnregister);
1845         else
1846         {
1847             LPWSTR lpszwReading = strdupAtoW(lpszReading);
1848             LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
1849             BOOL rc;
1850
1851             rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
1852             HeapFree(GetProcessHeap(),0,lpszwReading);
1853             HeapFree(GetProcessHeap(),0,lpszwUnregister);
1854             return rc;
1855         }
1856     }
1857     else
1858         return FALSE;
1859 }
1860
1861 /***********************************************************************
1862  *              ImmUnregisterWordW (IMM32.@)
1863  */
1864 BOOL WINAPI ImmUnregisterWordW(
1865   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
1866 {
1867     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1868     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
1869             debugstr_w(lpszUnregister));
1870     if (immHkl->hIME && immHkl->pImeUnregisterWord)
1871     {
1872         if (is_kbd_ime_unicode(immHkl))
1873             return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
1874         else
1875         {
1876             LPSTR lpszaReading = strdupWtoA(lpszReading);
1877             LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
1878             BOOL rc;
1879
1880             rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
1881                                             (LPCWSTR)lpszaUnregister);
1882             HeapFree(GetProcessHeap(),0,lpszaReading);
1883             HeapFree(GetProcessHeap(),0,lpszaUnregister);
1884             return rc;
1885         }
1886     }
1887     else
1888         return FALSE;
1889 }
1890
1891 /***********************************************************************
1892  *              ImmGetImeMenuItemsA (IMM32.@)
1893  */
1894 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
1895    LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
1896     DWORD dwSize)
1897 {
1898     InputContextData *data = (InputContextData*)hIMC;
1899     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1900         lpImeParentMenu, lpImeMenu, dwSize);
1901     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1902     {
1903         if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1904             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1905                                 (IMEMENUITEMINFOW*)lpImeParentMenu,
1906                                 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
1907         else
1908         {
1909             IMEMENUITEMINFOW lpImeParentMenuW;
1910             IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
1911             DWORD rc;
1912
1913             if (lpImeParentMenu)
1914                 parent = &lpImeParentMenuW;
1915             if (lpImeMenu)
1916             {
1917                 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
1918                 dwSize = count * sizeof(IMEMENUITEMINFOW);
1919                 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
1920             }
1921             else
1922                 lpImeMenuW = NULL;
1923
1924             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1925                                 parent, lpImeMenuW, dwSize);
1926
1927             if (lpImeParentMenu)
1928             {
1929                 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
1930                 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
1931                 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
1932                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
1933                     NULL, NULL);
1934             }
1935             if (lpImeMenu && rc)
1936             {
1937                 int i;
1938                 for (i = 0; i < rc; i++)
1939                 {
1940                     memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
1941                     lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
1942                     WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
1943                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
1944                         NULL, NULL);
1945                 }
1946             }
1947             HeapFree(GetProcessHeap(),0,lpImeMenuW);
1948             return rc;
1949         }
1950     }
1951     else
1952         return 0;
1953 }
1954
1955 /***********************************************************************
1956 *               ImmGetImeMenuItemsW (IMM32.@)
1957 */
1958 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
1959    LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
1960    DWORD dwSize)
1961 {
1962     InputContextData *data = (InputContextData*)hIMC;
1963     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1964         lpImeParentMenu, lpImeMenu, dwSize);
1965     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1966     {
1967         if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1968             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1969                                 lpImeParentMenu, lpImeMenu, dwSize);
1970         else
1971         {
1972             IMEMENUITEMINFOA lpImeParentMenuA;
1973             IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
1974             DWORD rc;
1975
1976             if (lpImeParentMenu)
1977                 parent = &lpImeParentMenuA;
1978             if (lpImeMenu)
1979             {
1980                 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
1981                 dwSize = count * sizeof(IMEMENUITEMINFOA);
1982                 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
1983             }
1984             else
1985                 lpImeMenuA = NULL;
1986
1987             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1988                                 (IMEMENUITEMINFOW*)parent,
1989                                 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
1990
1991             if (lpImeParentMenu)
1992             {
1993                 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
1994                 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
1995                 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
1996                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
1997             }
1998             if (lpImeMenu && rc)
1999             {
2000                 int i;
2001                 for (i = 0; i < rc; i++)
2002                 {
2003                     memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2004                     lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2005                     MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2006                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2007                 }
2008             }
2009             HeapFree(GetProcessHeap(),0,lpImeMenuA);
2010             return rc;
2011         }
2012     }
2013     else
2014         return 0;
2015 }
2016
2017 /***********************************************************************
2018 *               ImmLockIMC(IMM32.@)
2019 */
2020 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2021 {
2022     InputContextData *data = (InputContextData*)hIMC;
2023
2024     if (!data)
2025         return NULL;
2026     data->dwLock++;
2027     return &data->IMC;
2028 }
2029
2030 /***********************************************************************
2031 *               ImmUnlockIMC(IMM32.@)
2032 */
2033 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2034 {
2035     InputContextData *data = (InputContextData*)hIMC;
2036     data->dwLock--;
2037     return (data->dwLock!=0);
2038 }
2039
2040 /***********************************************************************
2041 *               ImmGetIMCLockCount(IMM32.@)
2042 */
2043 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2044 {
2045     InputContextData *data = (InputContextData*)hIMC;
2046     return data->dwLock;
2047 }
2048
2049 /***********************************************************************
2050 *               ImmCreateIMCC(IMM32.@)
2051 */
2052 HIMCC  WINAPI ImmCreateIMCC(DWORD size)
2053 {
2054     IMCCInternal *internal;
2055     int real_size = size + sizeof(IMCCInternal);
2056
2057     internal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, real_size);
2058     if (internal == NULL)
2059         return NULL;
2060
2061     internal->dwSize = size;
2062     return  (HIMCC)internal;
2063 }
2064
2065 /***********************************************************************
2066 *       ImmDestroyIMCC(IMM32.@)
2067 */
2068 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2069 {
2070     HeapFree(GetProcessHeap(),0,block);
2071     return NULL;
2072 }
2073
2074 /***********************************************************************
2075 *               ImmLockIMCC(IMM32.@)
2076 */
2077 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2078 {
2079     IMCCInternal *internal;
2080     internal = (IMCCInternal*) imcc;
2081
2082     internal->dwLock ++;
2083     return internal + 1;
2084 }
2085
2086 /***********************************************************************
2087 *               ImmUnlockIMCC(IMM32.@)
2088 */
2089 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2090 {
2091     IMCCInternal *internal;
2092     internal = (IMCCInternal*) imcc;
2093
2094     internal->dwLock --;
2095     return (internal->dwLock!=0);
2096 }
2097
2098 /***********************************************************************
2099 *               ImmGetIMCCLockCount(IMM32.@)
2100 */
2101 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2102 {
2103     IMCCInternal *internal;
2104     internal = (IMCCInternal*) imcc;
2105
2106     return internal->dwLock;
2107 }
2108
2109 /***********************************************************************
2110 *               ImmReSizeIMCC(IMM32.@)
2111 */
2112 HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2113 {
2114     IMCCInternal *internal,*newone;
2115     int real_size = size + sizeof(IMCCInternal);
2116
2117     internal = (IMCCInternal*) imcc;
2118
2119     newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size);
2120     newone->dwSize = size;
2121
2122     return newone;
2123 }
2124
2125 /***********************************************************************
2126 *               ImmGetIMCCSize(IMM32.@)
2127 */
2128 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2129 {
2130     IMCCInternal *internal;
2131     internal = (IMCCInternal*) imcc;
2132
2133     return internal->dwSize;
2134 }
2135
2136 /***********************************************************************
2137 *               ImmGenerateMessage(IMM32.@)
2138 */
2139 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2140 {
2141     InputContextData *data = (InputContextData*)hIMC;
2142
2143     TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
2144     if (data->IMC.dwNumMsgBuf > 0)
2145     {
2146         LPTRANSMSG lpTransMsg;
2147         INT i;
2148
2149         lpTransMsg = (LPTRANSMSG)ImmLockIMCC(data->IMC.hMsgBuf);
2150         for (i = 0; i < data->IMC.dwNumMsgBuf; i++)
2151             ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
2152
2153         ImmUnlockIMCC(data->IMC.hMsgBuf);
2154
2155         data->IMC.dwNumMsgBuf = 0;
2156     }
2157
2158     return TRUE;
2159 }
2160
2161 /***********************************************************************
2162 *       ImmTranslateMessage(IMM32.@)
2163 *       ( Undocumented, call internally and from user32.dll )
2164 */
2165 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WCHAR chr, LPARAM lKeyData)
2166 {
2167     InputContextData *data;
2168     HIMC imc = ImmGetContext(hwnd);
2169     BYTE state[256];
2170     UINT scancode;
2171     LPVOID list = 0;
2172     UINT msg_count;
2173     UINT uVirtKey;
2174     static const int list_count = 10;
2175
2176     TRACE("%p %x '%c' %x\n",hwnd, msg, chr, (UINT)lKeyData);
2177
2178     if (imc)
2179         data = (InputContextData*)imc;
2180     else
2181         return FALSE;
2182
2183     if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
2184         return FALSE;
2185
2186     GetKeyboardState(state);
2187     scancode = lKeyData >> 0x10 & 0xff;
2188
2189     list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
2190     ((DWORD*)list)[0] = list_count;
2191
2192     if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
2193     {
2194         if (!is_himc_ime_unicode(data))
2195             ToAscii(data->lastVK, scancode, state, &chr, 0);
2196         uVirtKey = MAKELONG(data->lastVK,chr);
2197     }
2198     else
2199         uVirtKey = data->lastVK;
2200
2201     msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
2202     TRACE("%i messages generated\n",msg_count);
2203     if (msg_count && msg_count <= list_count)
2204     {
2205         int i;
2206         LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
2207
2208         for (i = 0; i < msg_count; i++)
2209             ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
2210     }
2211     else if (msg_count > list_count)
2212         ImmGenerateMessage(imc);
2213
2214     HeapFree(GetProcessHeap(),0,list);
2215
2216     return (msg_count > 0);
2217 }
2218
2219 /***********************************************************************
2220 *               ImmProcessKey(IMM32.@)
2221 *       ( Undocumented, called from user32.dll )
2222 */
2223 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
2224 {
2225     InputContextData *data;
2226     HIMC imc = ImmGetContext(hwnd);
2227     BYTE state[256];
2228
2229     TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
2230
2231     if (imc)
2232         data = (InputContextData*)imc;
2233     else
2234         return FALSE;
2235
2236     if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
2237         return FALSE;
2238
2239     GetKeyboardState(state);
2240     data->lastVK = vKey;
2241
2242     if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
2243     {
2244         WCHAR key;
2245         UINT scancode;
2246
2247         scancode = lKeyData >> 0x10 & 0xff;
2248         ToUnicodeEx(vKey, scancode, state, &key, 1, 0, hKL);
2249         return ImmTranslateMessage(hwnd, WM_KEYDOWN, key, lKeyData );
2250     }
2251
2252     return FALSE;
2253 }