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