imm32: Fix a typo.
[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     InputContextData *data = (InputContextData*)hIMC;
1099
1100     TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1101
1102     if (!data)
1103         return FALSE;
1104
1105     if (lpfdwConversion)
1106         *lpfdwConversion = data->IMC.fdwConversion;
1107     if (lpfdwSentence)
1108         *lpfdwSentence = data->IMC.fdwSentence;
1109
1110     return TRUE;
1111 }
1112
1113 /***********************************************************************
1114  *              ImmGetDefaultIMEWnd (IMM32.@)
1115  */
1116 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1117 {
1118     TRACE("Default is %x\n",(unsigned)IMM_GetThreadData()->hwndDefault);
1119     return IMM_GetThreadData()->hwndDefault;
1120 }
1121
1122 /***********************************************************************
1123  *              ImmGetDescriptionA (IMM32.@)
1124  */
1125 UINT WINAPI ImmGetDescriptionA(
1126   HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1127 {
1128   WCHAR *buf;
1129   DWORD len;
1130
1131   TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1132
1133   /* find out how many characters in the unicode buffer */
1134   len = ImmGetDescriptionW( hKL, NULL, 0 );
1135
1136   /* allocate a buffer of that size */
1137   buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1138   if( !buf )
1139   return 0;
1140
1141   /* fetch the unicode buffer */
1142   len = ImmGetDescriptionW( hKL, buf, len + 1 );
1143
1144   /* convert it back to ASCII */
1145   len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1146                              lpszDescription, uBufLen, NULL, NULL );
1147
1148   HeapFree( GetProcessHeap(), 0, buf );
1149
1150   return len;
1151 }
1152
1153 /***********************************************************************
1154  *              ImmGetDescriptionW (IMM32.@)
1155  */
1156 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1157 {
1158   static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 };
1159
1160   FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1161
1162   if (!uBufLen) return lstrlenW( name );
1163   lstrcpynW( lpszDescription, name, uBufLen );
1164   return lstrlenW( lpszDescription );
1165 }
1166
1167 /***********************************************************************
1168  *              ImmGetGuideLineA (IMM32.@)
1169  */
1170 DWORD WINAPI ImmGetGuideLineA(
1171   HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1172 {
1173   FIXME("(%p, %d, %s, %d): stub\n",
1174     hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1175   );
1176   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1177   return 0;
1178 }
1179
1180 /***********************************************************************
1181  *              ImmGetGuideLineW (IMM32.@)
1182  */
1183 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1184 {
1185   FIXME("(%p, %d, %s, %d): stub\n",
1186     hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1187   );
1188   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1189   return 0;
1190 }
1191
1192 /***********************************************************************
1193  *              ImmGetIMEFileNameA (IMM32.@)
1194  */
1195 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1196 {
1197     LPWSTR bufW = NULL;
1198     UINT wBufLen = uBufLen;
1199     UINT rc;
1200
1201     if (uBufLen && lpszFileName)
1202         bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1203     else /* We need this to get the number of byte required */
1204     {
1205         bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1206         wBufLen = MAX_PATH;
1207     }
1208
1209     rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1210
1211     if (rc > 0)
1212     {
1213         if (uBufLen && lpszFileName)
1214             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1215                                  uBufLen, NULL, NULL);
1216         else /* get the length */
1217             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1218                                      NULL);
1219     }
1220
1221     HeapFree(GetProcessHeap(),0,bufW);
1222     return rc;
1223 }
1224
1225 /***********************************************************************
1226  *              ImmGetIMEFileNameW (IMM32.@)
1227  */
1228 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1229 {
1230     static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
1231     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};
1232
1233     HKEY hkey;
1234     DWORD length;
1235     DWORD rc;
1236     WCHAR regKey[sizeof(fmt)/sizeof(WCHAR)+8];
1237
1238     wsprintfW( regKey, fmt, (unsigned)hKL );
1239     rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1240     if (rc != ERROR_SUCCESS)
1241     {
1242         SetLastError(rc);
1243         return 0;
1244     }
1245
1246     length = 0;
1247     rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length);
1248
1249     if (rc != ERROR_SUCCESS)
1250     {
1251         RegCloseKey(hkey);
1252         SetLastError(rc);
1253         return 0;
1254     }
1255     if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1256     {
1257         RegCloseKey(hkey);
1258         if (lpszFileName)
1259         {
1260             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1261             return 0;
1262         }
1263         else
1264             return length / sizeof(WCHAR);
1265     }
1266
1267     RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1268
1269     RegCloseKey(hkey);
1270
1271     return length / sizeof(WCHAR);
1272 }
1273
1274 /***********************************************************************
1275  *              ImmGetOpenStatus (IMM32.@)
1276  */
1277 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1278 {
1279   InputContextData *data = (InputContextData*)hIMC;
1280
1281     if (!data)
1282         return FALSE;
1283   FIXME("(%p): semi-stub\n", hIMC);
1284
1285   return data->IMC.fOpen;
1286 }
1287
1288 /***********************************************************************
1289  *              ImmGetProperty (IMM32.@)
1290  */
1291 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1292 {
1293     DWORD rc = 0;
1294     ImmHkl *kbd;
1295
1296     TRACE("(%p, %d)\n", hKL, fdwIndex);
1297     kbd = IMM_GetImmHkl(hKL);
1298
1299     if (kbd && kbd->hIME)
1300     {
1301         switch (fdwIndex)
1302         {
1303             case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
1304             case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
1305             case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
1306             case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
1307             case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
1308             case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
1309             case IGP_UI: rc = 0; break;
1310             default: rc = 0;
1311         }
1312     }
1313     return rc;
1314 }
1315
1316 /***********************************************************************
1317  *              ImmGetRegisterWordStyleA (IMM32.@)
1318  */
1319 UINT WINAPI ImmGetRegisterWordStyleA(
1320   HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1321 {
1322     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1323     TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1324     if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1325     {
1326         if (!is_kbd_ime_unicode(immHkl))
1327             return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
1328         else
1329         {
1330             STYLEBUFW sbw;
1331             UINT rc;
1332
1333             rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
1334             WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
1335                 lpStyleBuf->szDescription, 32, NULL, NULL);
1336             lpStyleBuf->dwStyle = sbw.dwStyle;
1337             return rc;
1338         }
1339     }
1340     else
1341         return 0;
1342 }
1343
1344 /***********************************************************************
1345  *              ImmGetRegisterWordStyleW (IMM32.@)
1346  */
1347 UINT WINAPI ImmGetRegisterWordStyleW(
1348   HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1349 {
1350     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1351     TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1352     if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1353     {
1354         if (is_kbd_ime_unicode(immHkl))
1355             return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
1356         else
1357         {
1358             STYLEBUFA sba;
1359             UINT rc;
1360
1361             rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
1362             MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
1363                 lpStyleBuf->szDescription, 32);
1364             lpStyleBuf->dwStyle = sba.dwStyle;
1365             return rc;
1366         }
1367     }
1368     else
1369         return 0;
1370 }
1371
1372 /***********************************************************************
1373  *              ImmGetStatusWindowPos (IMM32.@)
1374  */
1375 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1376 {
1377   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
1378   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1379   return FALSE;
1380 }
1381
1382 /***********************************************************************
1383  *              ImmGetVirtualKey (IMM32.@)
1384  */
1385 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
1386 {
1387   OSVERSIONINFOA version;
1388   InputContextData *data = (InputContextData *)ImmGetContext( hWnd );
1389   TRACE("%p\n", hWnd);
1390
1391   if ( data )
1392       return data->lastVK;
1393
1394   GetVersionExA( &version );
1395   switch(version.dwPlatformId)
1396   {
1397   case VER_PLATFORM_WIN32_WINDOWS:
1398       return VK_PROCESSKEY;
1399   case VER_PLATFORM_WIN32_NT:
1400       return 0;
1401   default:
1402       FIXME("%d not supported\n",version.dwPlatformId);
1403       return VK_PROCESSKEY;
1404   }
1405 }
1406
1407 /***********************************************************************
1408  *              ImmInstallIMEA (IMM32.@)
1409  */
1410 HKL WINAPI ImmInstallIMEA(
1411   LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
1412 {
1413   FIXME("(%s, %s): stub\n",
1414     debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText)
1415   );
1416   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1417   return NULL;
1418 }
1419
1420 /***********************************************************************
1421  *              ImmInstallIMEW (IMM32.@)
1422  */
1423 HKL WINAPI ImmInstallIMEW(
1424   LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
1425 {
1426   FIXME("(%s, %s): stub\n",
1427     debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText)
1428   );
1429   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1430   return NULL;
1431 }
1432
1433 /***********************************************************************
1434  *              ImmIsIME (IMM32.@)
1435  */
1436 BOOL WINAPI ImmIsIME(HKL hKL)
1437 {
1438     ImmHkl *ptr;
1439     TRACE("(%p):\n", hKL);
1440     ptr = IMM_GetImmHkl(hKL);
1441     return (ptr && ptr->hIME);
1442 }
1443
1444 /***********************************************************************
1445  *              ImmIsUIMessageA (IMM32.@)
1446  */
1447 BOOL WINAPI ImmIsUIMessageA(
1448   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
1449 {
1450     BOOL rc = FALSE;
1451
1452     TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
1453     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1454         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
1455         (msg == WM_MSIME_SERVICE) ||
1456         (msg == WM_MSIME_RECONVERTOPTIONS) ||
1457         (msg == WM_MSIME_MOUSE) ||
1458         (msg == WM_MSIME_RECONVERTREQUEST) ||
1459         (msg == WM_MSIME_RECONVERT) ||
1460         (msg == WM_MSIME_QUERYPOSITION) ||
1461         (msg == WM_MSIME_DOCUMENTFEED))
1462
1463     {
1464         if (!IMM_GetThreadData()->hwndDefault)
1465             ImmGetDefaultIMEWnd(NULL);
1466
1467         if (hWndIME == NULL)
1468             PostMessageA(IMM_GetThreadData()->hwndDefault, msg, wParam, lParam);
1469
1470         rc = TRUE;
1471     }
1472     return rc;
1473 }
1474
1475 /***********************************************************************
1476  *              ImmIsUIMessageW (IMM32.@)
1477  */
1478 BOOL WINAPI ImmIsUIMessageW(
1479   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
1480 {
1481     BOOL rc = FALSE;
1482     TRACE("(%p, %d, %ld, %ld):\n", hWndIME, msg, wParam, lParam);
1483     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1484         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
1485         (msg == WM_MSIME_SERVICE) ||
1486         (msg == WM_MSIME_RECONVERTOPTIONS) ||
1487         (msg == WM_MSIME_MOUSE) ||
1488         (msg == WM_MSIME_RECONVERTREQUEST) ||
1489         (msg == WM_MSIME_RECONVERT) ||
1490         (msg == WM_MSIME_QUERYPOSITION) ||
1491         (msg == WM_MSIME_DOCUMENTFEED))
1492         rc = TRUE;
1493     return rc;
1494 }
1495
1496 /***********************************************************************
1497  *              ImmNotifyIME (IMM32.@)
1498  */
1499 BOOL WINAPI ImmNotifyIME(
1500   HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1501 {
1502     InputContextData *data = (InputContextData*)hIMC;
1503
1504     TRACE("(%p, %d, %d, %d)\n",
1505         hIMC, dwAction, dwIndex, dwValue);
1506
1507     if (!data || ! data->immKbd->pNotifyIME)
1508         return FALSE;
1509
1510     return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
1511 }
1512
1513 /***********************************************************************
1514  *              ImmRegisterWordA (IMM32.@)
1515  */
1516 BOOL WINAPI ImmRegisterWordA(
1517   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
1518 {
1519     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1520     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
1521                     debugstr_a(lpszRegister));
1522     if (immHkl->hIME && immHkl->pImeRegisterWord)
1523     {
1524         if (!is_kbd_ime_unicode(immHkl))
1525             return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
1526                                             (LPCWSTR)lpszRegister);
1527         else
1528         {
1529             LPWSTR lpszwReading = strdupAtoW(lpszReading);
1530             LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
1531             BOOL rc;
1532
1533             rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
1534             HeapFree(GetProcessHeap(),0,lpszwReading);
1535             HeapFree(GetProcessHeap(),0,lpszwRegister);
1536             return rc;
1537         }
1538     }
1539     else
1540         return FALSE;
1541 }
1542
1543 /***********************************************************************
1544  *              ImmRegisterWordW (IMM32.@)
1545  */
1546 BOOL WINAPI ImmRegisterWordW(
1547   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
1548 {
1549     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1550     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
1551                     debugstr_w(lpszRegister));
1552     if (immHkl->hIME && immHkl->pImeRegisterWord)
1553     {
1554         if (is_kbd_ime_unicode(immHkl))
1555             return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
1556         else
1557         {
1558             LPSTR lpszaReading = strdupWtoA(lpszReading);
1559             LPSTR lpszaRegister = strdupWtoA(lpszRegister);
1560             BOOL rc;
1561
1562             rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
1563                                           (LPCWSTR)lpszaRegister);
1564             HeapFree(GetProcessHeap(),0,lpszaReading);
1565             HeapFree(GetProcessHeap(),0,lpszaRegister);
1566             return rc;
1567         }
1568     }
1569     else
1570         return FALSE;
1571 }
1572
1573 /***********************************************************************
1574  *              ImmReleaseContext (IMM32.@)
1575  */
1576 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1577 {
1578   static int shown = 0;
1579
1580   if (!shown) {
1581      FIXME("(%p, %p): stub\n", hWnd, hIMC);
1582      shown = 1;
1583   }
1584   return TRUE;
1585 }
1586
1587 /***********************************************************************
1588 *              ImmRequestMessageA(IMM32.@)
1589 */
1590 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
1591 {
1592     FIXME("(%p %ld %ld): stub\n", hIMC, wParam, wParam);
1593     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1594     return 0;
1595 }
1596
1597 /***********************************************************************
1598 *              ImmRequestMessageW(IMM32.@)
1599 */
1600 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
1601 {
1602     FIXME("(%p %ld %ld): stub\n", hIMC, wParam, wParam);
1603     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1604     return 0;
1605 }
1606
1607 /***********************************************************************
1608  *              ImmSetCandidateWindow (IMM32.@)
1609  */
1610 BOOL WINAPI ImmSetCandidateWindow(
1611   HIMC hIMC, LPCANDIDATEFORM lpCandidate)
1612 {
1613   FIXME("(%p, %p): stub\n", hIMC, lpCandidate);
1614   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1615   return FALSE;
1616 }
1617
1618 /***********************************************************************
1619  *              ImmSetCompositionFontA (IMM32.@)
1620  */
1621 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1622 {
1623     InputContextData *data = (InputContextData*)hIMC;
1624     TRACE("(%p, %p)\n", hIMC, lplf);
1625
1626     if (!data)
1627         return FALSE;
1628
1629     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
1630     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
1631                         LF_FACESIZE);
1632     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1633
1634     return TRUE;
1635 }
1636
1637 /***********************************************************************
1638  *              ImmSetCompositionFontW (IMM32.@)
1639  */
1640 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1641 {
1642     InputContextData *data = (InputContextData*)hIMC;
1643     TRACE("(%p, %p)\n", hIMC, lplf);
1644
1645     if (!data)
1646         return FALSE;
1647
1648     data->IMC.lfFont.W = *lplf;
1649     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1650
1651     return TRUE;
1652 }
1653
1654 /***********************************************************************
1655  *              ImmSetCompositionStringA (IMM32.@)
1656  */
1657 BOOL WINAPI ImmSetCompositionStringA(
1658   HIMC hIMC, DWORD dwIndex,
1659   LPCVOID lpComp, DWORD dwCompLen,
1660   LPCVOID lpRead, DWORD dwReadLen)
1661 {
1662     DWORD comp_len;
1663     DWORD read_len;
1664     WCHAR *CompBuffer = NULL;
1665     WCHAR *ReadBuffer = NULL;
1666     BOOL rc;
1667     InputContextData *data = (InputContextData*)hIMC;
1668
1669     TRACE("(%p, %d, %p, %d, %p, %d):\n",
1670             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1671
1672     if (!data)
1673         return FALSE;
1674
1675     if (!is_himc_ime_unicode(data))
1676         return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1677                         dwCompLen, lpRead, dwReadLen);
1678
1679     comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
1680     if (comp_len)
1681     {
1682         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
1683         MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
1684     }
1685
1686     read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
1687     if (read_len)
1688     {
1689         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
1690         MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
1691     }
1692
1693     rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
1694                                    ReadBuffer, read_len);
1695
1696     HeapFree(GetProcessHeap(), 0, CompBuffer);
1697     HeapFree(GetProcessHeap(), 0, ReadBuffer);
1698
1699     return rc;
1700 }
1701
1702 /***********************************************************************
1703  *              ImmSetCompositionStringW (IMM32.@)
1704  */
1705 BOOL WINAPI ImmSetCompositionStringW(
1706         HIMC hIMC, DWORD dwIndex,
1707         LPCVOID lpComp, DWORD dwCompLen,
1708         LPCVOID lpRead, DWORD dwReadLen)
1709 {
1710     DWORD comp_len;
1711     DWORD read_len;
1712     CHAR *CompBuffer = NULL;
1713     CHAR *ReadBuffer = NULL;
1714     BOOL rc;
1715     InputContextData *data = (InputContextData*)hIMC;
1716
1717     TRACE("(%p, %d, %p, %d, %p, %d):\n",
1718             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1719
1720     if (!data)
1721         return FALSE;
1722
1723     if (is_himc_ime_unicode(data))
1724         return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1725                         dwCompLen, lpRead, dwReadLen);
1726
1727     comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
1728                                    NULL);
1729     if (comp_len)
1730     {
1731         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
1732         WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
1733                             NULL, NULL);
1734     }
1735
1736     read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
1737                                    NULL);
1738     if (read_len)
1739     {
1740         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
1741         WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
1742                             NULL, NULL);
1743     }
1744
1745     rc =  ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
1746                                    ReadBuffer, read_len);
1747
1748     HeapFree(GetProcessHeap(), 0, CompBuffer);
1749     HeapFree(GetProcessHeap(), 0, ReadBuffer);
1750
1751     return rc;
1752 }
1753
1754 /***********************************************************************
1755  *              ImmSetCompositionWindow (IMM32.@)
1756  */
1757 BOOL WINAPI ImmSetCompositionWindow(
1758   HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1759 {
1760     BOOL reshow = FALSE;
1761     InputContextData *data = (InputContextData*)hIMC;
1762
1763     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1764     TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
1765           lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top,
1766           lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right);
1767
1768     if (!data)
1769         return FALSE;
1770
1771     data->IMC.cfCompForm = *lpCompForm;
1772
1773     if (IsWindowVisible(IMM_GetThreadData()->hwndDefault))
1774     {
1775         reshow = TRUE;
1776         ShowWindow(IMM_GetThreadData()->hwndDefault,SW_HIDE);
1777     }
1778
1779     /* FIXME: this is a partial stub */
1780
1781     if (reshow)
1782         ShowWindow(IMM_GetThreadData()->hwndDefault,SW_SHOWNOACTIVATE);
1783
1784     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
1785     return TRUE;
1786 }
1787
1788 /***********************************************************************
1789  *              ImmSetConversionStatus (IMM32.@)
1790  */
1791 BOOL WINAPI ImmSetConversionStatus(
1792   HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1793 {
1794     DWORD oldConversion, oldSentence;
1795     InputContextData *data = (InputContextData*)hIMC;
1796
1797     TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
1798
1799     if (!data)
1800         return FALSE;
1801
1802     if ( fdwConversion != data->IMC.fdwConversion )
1803     {
1804         oldConversion = data->IMC.fdwConversion;
1805         data->IMC.fdwConversion = fdwConversion;
1806         ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
1807         ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
1808     }
1809     if ( fdwSentence != data->IMC.fdwSentence )
1810     {
1811         oldSentence = data->IMC.fdwSentence;
1812         data->IMC.fdwSentence = fdwSentence;
1813         ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
1814         ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
1815     }
1816
1817     return TRUE;
1818 }
1819
1820 /***********************************************************************
1821  *              ImmSetOpenStatus (IMM32.@)
1822  */
1823 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
1824 {
1825     InputContextData *data = (InputContextData*)hIMC;
1826
1827     TRACE("%p %d\n", hIMC, fOpen);
1828
1829     if (!data)
1830         return FALSE;
1831
1832     if (data->imeWnd == NULL)
1833     {
1834         /* create the ime window */
1835         data->imeWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
1836                     data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
1837                     0, data->immKbd->hIME, 0);
1838         SetWindowLongW(data->imeWnd, IMMGWL_IMC, (LONG)data);
1839         IMM_GetThreadData()->hwndDefault = data->imeWnd;
1840     }
1841
1842     if (!fOpen != !data->IMC.fOpen)
1843     {
1844         data->IMC.fOpen = fOpen;
1845         ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
1846         ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
1847     }
1848
1849     return TRUE;
1850 }
1851
1852 /***********************************************************************
1853  *              ImmSetStatusWindowPos (IMM32.@)
1854  */
1855 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1856 {
1857   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
1858   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1859   return FALSE;
1860 }
1861
1862 /***********************************************************************
1863  *              ImmCreateSoftKeyboard(IMM32.@)
1864  */
1865 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
1866 {
1867     FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
1868     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1869     return 0;
1870 }
1871
1872 /***********************************************************************
1873  *              ImmDestroySoftKeyboard(IMM32.@)
1874  */
1875 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
1876 {
1877     FIXME("(%p): stub\n", hSoftWnd);
1878     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1879     return FALSE;
1880 }
1881
1882 /***********************************************************************
1883  *              ImmShowSoftKeyboard(IMM32.@)
1884  */
1885 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
1886 {
1887     FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
1888     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1889     return FALSE;
1890 }
1891
1892 /***********************************************************************
1893  *              ImmSimulateHotKey (IMM32.@)
1894  */
1895 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
1896 {
1897   FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
1898   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1899   return FALSE;
1900 }
1901
1902 /***********************************************************************
1903  *              ImmUnregisterWordA (IMM32.@)
1904  */
1905 BOOL WINAPI ImmUnregisterWordA(
1906   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
1907 {
1908     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1909     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
1910             debugstr_a(lpszUnregister));
1911     if (immHkl->hIME && immHkl->pImeUnregisterWord)
1912     {
1913         if (!is_kbd_ime_unicode(immHkl))
1914             return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
1915                                               (LPCWSTR)lpszUnregister);
1916         else
1917         {
1918             LPWSTR lpszwReading = strdupAtoW(lpszReading);
1919             LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
1920             BOOL rc;
1921
1922             rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
1923             HeapFree(GetProcessHeap(),0,lpszwReading);
1924             HeapFree(GetProcessHeap(),0,lpszwUnregister);
1925             return rc;
1926         }
1927     }
1928     else
1929         return FALSE;
1930 }
1931
1932 /***********************************************************************
1933  *              ImmUnregisterWordW (IMM32.@)
1934  */
1935 BOOL WINAPI ImmUnregisterWordW(
1936   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
1937 {
1938     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1939     TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
1940             debugstr_w(lpszUnregister));
1941     if (immHkl->hIME && immHkl->pImeUnregisterWord)
1942     {
1943         if (is_kbd_ime_unicode(immHkl))
1944             return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
1945         else
1946         {
1947             LPSTR lpszaReading = strdupWtoA(lpszReading);
1948             LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
1949             BOOL rc;
1950
1951             rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
1952                                             (LPCWSTR)lpszaUnregister);
1953             HeapFree(GetProcessHeap(),0,lpszaReading);
1954             HeapFree(GetProcessHeap(),0,lpszaUnregister);
1955             return rc;
1956         }
1957     }
1958     else
1959         return FALSE;
1960 }
1961
1962 /***********************************************************************
1963  *              ImmGetImeMenuItemsA (IMM32.@)
1964  */
1965 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
1966    LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
1967     DWORD dwSize)
1968 {
1969     InputContextData *data = (InputContextData*)hIMC;
1970     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1971         lpImeParentMenu, lpImeMenu, dwSize);
1972     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1973     {
1974         if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1975             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1976                                 (IMEMENUITEMINFOW*)lpImeParentMenu,
1977                                 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
1978         else
1979         {
1980             IMEMENUITEMINFOW lpImeParentMenuW;
1981             IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
1982             DWORD rc;
1983
1984             if (lpImeParentMenu)
1985                 parent = &lpImeParentMenuW;
1986             if (lpImeMenu)
1987             {
1988                 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
1989                 dwSize = count * sizeof(IMEMENUITEMINFOW);
1990                 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
1991             }
1992             else
1993                 lpImeMenuW = NULL;
1994
1995             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1996                                 parent, lpImeMenuW, dwSize);
1997
1998             if (lpImeParentMenu)
1999             {
2000                 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2001                 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2002                 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2003                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2004                     NULL, NULL);
2005             }
2006             if (lpImeMenu && rc)
2007             {
2008                 int i;
2009                 for (i = 0; i < rc; i++)
2010                 {
2011                     memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2012                     lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2013                     WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2014                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2015                         NULL, NULL);
2016                 }
2017             }
2018             HeapFree(GetProcessHeap(),0,lpImeMenuW);
2019             return rc;
2020         }
2021     }
2022     else
2023         return 0;
2024 }
2025
2026 /***********************************************************************
2027 *               ImmGetImeMenuItemsW (IMM32.@)
2028 */
2029 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2030    LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2031    DWORD dwSize)
2032 {
2033     InputContextData *data = (InputContextData*)hIMC;
2034     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2035         lpImeParentMenu, lpImeMenu, dwSize);
2036     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2037     {
2038         if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2039             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2040                                 lpImeParentMenu, lpImeMenu, dwSize);
2041         else
2042         {
2043             IMEMENUITEMINFOA lpImeParentMenuA;
2044             IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2045             DWORD rc;
2046
2047             if (lpImeParentMenu)
2048                 parent = &lpImeParentMenuA;
2049             if (lpImeMenu)
2050             {
2051                 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2052                 dwSize = count * sizeof(IMEMENUITEMINFOA);
2053                 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2054             }
2055             else
2056                 lpImeMenuA = NULL;
2057
2058             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2059                                 (IMEMENUITEMINFOW*)parent,
2060                                 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2061
2062             if (lpImeParentMenu)
2063             {
2064                 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2065                 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2066                 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2067                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2068             }
2069             if (lpImeMenu && rc)
2070             {
2071                 int i;
2072                 for (i = 0; i < rc; i++)
2073                 {
2074                     memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2075                     lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2076                     MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2077                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2078                 }
2079             }
2080             HeapFree(GetProcessHeap(),0,lpImeMenuA);
2081             return rc;
2082         }
2083     }
2084     else
2085         return 0;
2086 }
2087
2088 /***********************************************************************
2089 *               ImmLockIMC(IMM32.@)
2090 */
2091 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2092 {
2093     InputContextData *data = (InputContextData*)hIMC;
2094
2095     if (!data)
2096         return NULL;
2097     data->dwLock++;
2098     return &data->IMC;
2099 }
2100
2101 /***********************************************************************
2102 *               ImmUnlockIMC(IMM32.@)
2103 */
2104 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2105 {
2106     InputContextData *data = (InputContextData*)hIMC;
2107     data->dwLock--;
2108     return (data->dwLock!=0);
2109 }
2110
2111 /***********************************************************************
2112 *               ImmGetIMCLockCount(IMM32.@)
2113 */
2114 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2115 {
2116     InputContextData *data = (InputContextData*)hIMC;
2117     return data->dwLock;
2118 }
2119
2120 /***********************************************************************
2121 *               ImmCreateIMCC(IMM32.@)
2122 */
2123 HIMCC  WINAPI ImmCreateIMCC(DWORD size)
2124 {
2125     IMCCInternal *internal;
2126     int real_size = size + sizeof(IMCCInternal);
2127
2128     internal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, real_size);
2129     if (internal == NULL)
2130         return NULL;
2131
2132     internal->dwSize = size;
2133     return  (HIMCC)internal;
2134 }
2135
2136 /***********************************************************************
2137 *       ImmDestroyIMCC(IMM32.@)
2138 */
2139 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2140 {
2141     HeapFree(GetProcessHeap(),0,block);
2142     return NULL;
2143 }
2144
2145 /***********************************************************************
2146 *               ImmLockIMCC(IMM32.@)
2147 */
2148 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2149 {
2150     IMCCInternal *internal;
2151     internal = (IMCCInternal*) imcc;
2152
2153     internal->dwLock ++;
2154     return internal + 1;
2155 }
2156
2157 /***********************************************************************
2158 *               ImmUnlockIMCC(IMM32.@)
2159 */
2160 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2161 {
2162     IMCCInternal *internal;
2163     internal = (IMCCInternal*) imcc;
2164
2165     internal->dwLock --;
2166     return (internal->dwLock!=0);
2167 }
2168
2169 /***********************************************************************
2170 *               ImmGetIMCCLockCount(IMM32.@)
2171 */
2172 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2173 {
2174     IMCCInternal *internal;
2175     internal = (IMCCInternal*) imcc;
2176
2177     return internal->dwLock;
2178 }
2179
2180 /***********************************************************************
2181 *               ImmReSizeIMCC(IMM32.@)
2182 */
2183 HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2184 {
2185     IMCCInternal *internal,*newone;
2186     int real_size = size + sizeof(IMCCInternal);
2187
2188     internal = (IMCCInternal*) imcc;
2189
2190     newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size);
2191     newone->dwSize = size;
2192
2193     return newone;
2194 }
2195
2196 /***********************************************************************
2197 *               ImmGetIMCCSize(IMM32.@)
2198 */
2199 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2200 {
2201     IMCCInternal *internal;
2202     internal = (IMCCInternal*) imcc;
2203
2204     return internal->dwSize;
2205 }
2206
2207 /***********************************************************************
2208 *               ImmGenerateMessage(IMM32.@)
2209 */
2210 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2211 {
2212     InputContextData *data = (InputContextData*)hIMC;
2213
2214     TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
2215     if (data->IMC.dwNumMsgBuf > 0)
2216     {
2217         LPTRANSMSG lpTransMsg;
2218         INT i;
2219
2220         lpTransMsg = (LPTRANSMSG)ImmLockIMCC(data->IMC.hMsgBuf);
2221         for (i = 0; i < data->IMC.dwNumMsgBuf; i++)
2222             ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
2223
2224         ImmUnlockIMCC(data->IMC.hMsgBuf);
2225
2226         data->IMC.dwNumMsgBuf = 0;
2227     }
2228
2229     return TRUE;
2230 }
2231
2232 /***********************************************************************
2233 *       ImmTranslateMessage(IMM32.@)
2234 *       ( Undocumented, call internally and from user32.dll )
2235 */
2236 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WCHAR chr, LPARAM lKeyData)
2237 {
2238     InputContextData *data;
2239     HIMC imc = ImmGetContext(hwnd);
2240     BYTE state[256];
2241     UINT scancode;
2242     LPVOID list = 0;
2243     UINT msg_count;
2244     UINT uVirtKey;
2245     static const int list_count = 10;
2246
2247     TRACE("%p %x %x %x\n",hwnd, msg, chr, (UINT)lKeyData);
2248
2249     if (imc)
2250         data = (InputContextData*)imc;
2251     else
2252         return FALSE;
2253
2254     if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
2255         return FALSE;
2256
2257     GetKeyboardState(state);
2258     scancode = lKeyData >> 0x10 & 0xff;
2259
2260     list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
2261     ((DWORD*)list)[0] = list_count;
2262
2263     if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
2264     {
2265         if (!is_himc_ime_unicode(data))
2266             ToAscii(data->lastVK, scancode, state, &chr, 0);
2267         else
2268             ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
2269         uVirtKey = MAKELONG(data->lastVK,chr);
2270     }
2271     else
2272         uVirtKey = data->lastVK;
2273
2274     msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
2275     TRACE("%i messages generated\n",msg_count);
2276     if (msg_count && msg_count <= list_count)
2277     {
2278         int i;
2279         LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
2280
2281         for (i = 0; i < msg_count; i++)
2282             ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
2283     }
2284     else if (msg_count > list_count)
2285         ImmGenerateMessage(imc);
2286
2287     HeapFree(GetProcessHeap(),0,list);
2288
2289     data->lastVK = VK_PROCESSKEY;
2290
2291     return (msg_count > 0);
2292 }
2293
2294 /***********************************************************************
2295 *               ImmProcessKey(IMM32.@)
2296 *       ( Undocumented, called from user32.dll )
2297 */
2298 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
2299 {
2300     InputContextData *data;
2301     HIMC imc = ImmGetContext(hwnd);
2302     BYTE state[256];
2303
2304     TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
2305
2306     if (imc)
2307         data = (InputContextData*)imc;
2308     else
2309         return FALSE;
2310
2311     if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
2312         return FALSE;
2313
2314     GetKeyboardState(state);
2315     if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
2316     {
2317         data->lastVK = vKey;
2318         return TRUE;
2319     }
2320
2321     data->lastVK = VK_PROCESSKEY;
2322     return FALSE;
2323 }