~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/imm32/imm.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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     CHAR *buf;
995     LONG rc = 0;
996     InputContextData *data = (InputContextData*)hIMC;
997     LPCOMPOSITIONSTRING compstr;
998     LPBYTE compdata;
999 
1000     TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1001 
1002     if (!data)
1003        return FALSE;
1004 
1005     if (!data->IMC.hCompStr)
1006        return FALSE;
1007 
1008     compdata = ImmLockIMCC(data->IMC.hCompStr);
1009     compstr = (LPCOMPOSITIONSTRING)compdata;
1010 
1011     switch (dwIndex)
1012     {
1013     case GCS_RESULTSTR:
1014         if (compstr->dwResultStrLen > 0 && compstr->dwResultStrOffset > 0)
1015         {
1016             LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1017 
1018             TRACE("GCS_RESULTSTR %p %i\n",ResultStr,
1019                                         compstr->dwResultStrLen);
1020 
1021             buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwResultStrLen * 3 );
1022             rc = Wi