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