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