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