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