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