[IMM32] Rewrite IMCC handling functions (#3788)
[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 #ifdef __REACTOS__
1645 LPINPUTCONTEXT pIC;
1646
1647 TRACE("ImmGetConversionStatus(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
1648
1649 pIC = ImmLockIMC(hIMC);
1650 if (!pIC)
1651 return FALSE;
1652
1653 if (lpfdwConversion)
1654 *lpfdwConversion = pIC->fdwConversion;
1655 if (lpfdwSentence)
1656 *lpfdwSentence = pIC->fdwSentence;
1657
1658 ImmUnlockIMC(hIMC);
1659 return TRUE;
1660 #else
1661 InputContextData *data = get_imc_data(hIMC);
1662
1663 TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1664
1665 if (!data)
1666 return FALSE;
1667
1668 if (lpfdwConversion)
1669 *lpfdwConversion = data->IMC.fdwConversion;
1670 if (lpfdwSentence)
1671 *lpfdwSentence = data->IMC.fdwSentence;
1672
1673 return TRUE;
1674 #endif
1675 }
1676
1677 static BOOL needs_ime_window(HWND hwnd)
1678 {
1679 WCHAR classW[8];
1680
1681 if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, szwIME))
1682 return FALSE;
1683 if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
1684
1685 return TRUE;
1686 }
1687
1688 /***********************************************************************
1689 * __wine_register_window (IMM32.@)
1690 */
1691 BOOL WINAPI __wine_register_window(HWND hwnd)
1692 {
1693 HWND new = NULL;
1694 IMMThreadData *thread_data;
1695 TRACE("(%p)\n", hwnd);
1696
1697 if (!needs_ime_window(hwnd))
1698 return FALSE;
1699
1700 thread_data = IMM_GetThreadData(hwnd, 0);
1701 if (!thread_data)
1702 return FALSE;
1703
1704 if (thread_data->disableIME || disable_ime)
1705 {
1706 TRACE("IME for this thread is disabled\n");
1707 LeaveCriticalSection(&threaddata_cs);
1708 return FALSE;
1709 }
1710 thread_data->windowRefs++;
1711 TRACE("windowRefs=%u, hwndDefault=%p\n",
1712 thread_data->windowRefs, thread_data->hwndDefault);
1713
1714 /* Create default IME window */
1715 if (thread_data->windowRefs == 1)
1716 {
1717 /* Do not create the window inside of a critical section */
1718 LeaveCriticalSection(&threaddata_cs);
1719 new = CreateWindowExW( 0, szwIME, szwDefaultIME,
1720 WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
1721 0, 0, 1, 1, 0, 0, 0, 0);
1722 /* thread_data is in the current thread so we can assume it's still valid */
1723 EnterCriticalSection(&threaddata_cs);
1724 /* See if anyone beat us */
1725 if (thread_data->hwndDefault == NULL)
1726 {
1727 thread_data->hwndDefault = new;
1728 new = NULL;
1729 TRACE("Default is %p\n", thread_data->hwndDefault);
1730 }
1731 }
1732
1733 LeaveCriticalSection(&threaddata_cs);
1734
1735 /* Clean up an unused new window outside of the critical section */
1736 if (new != NULL)
1737 DestroyWindow(new);
1738 return TRUE;
1739 }
1740
1741 /***********************************************************************
1742 * __wine_unregister_window (IMM32.@)
1743 */
1744 void WINAPI __wine_unregister_window(HWND hwnd)
1745 {
1746 HWND to_destroy = 0;
1747 IMMThreadData *thread_data;
1748 TRACE("(%p)\n", hwnd);
1749
1750 thread_data = IMM_GetThreadData(hwnd, 0);
1751 if (!thread_data) return;
1752
1753 thread_data->windowRefs--;
1754 TRACE("windowRefs=%u, hwndDefault=%p\n",
1755 thread_data->windowRefs, thread_data->hwndDefault);
1756
1757 /* Destroy default IME window */
1758 if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
1759 {
1760 to_destroy = thread_data->hwndDefault;
1761 thread_data->hwndDefault = NULL;
1762 }
1763 LeaveCriticalSection(&threaddata_cs);
1764
1765 if (to_destroy) DestroyWindow( to_destroy );
1766 }
1767
1768 /***********************************************************************
1769 * ImmGetDefaultIMEWnd (IMM32.@)
1770 */
1771 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1772 {
1773 HWND ret;
1774 IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
1775 if (!thread_data)
1776 return NULL;
1777 ret = thread_data->hwndDefault;
1778 LeaveCriticalSection(&threaddata_cs);
1779 TRACE("Default is %p\n",ret);
1780 return ret;
1781 }
1782
1783 /***********************************************************************
1784 * ImmGetDescriptionA (IMM32.@)
1785 */
1786 UINT WINAPI ImmGetDescriptionA(
1787 HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1788 {
1789 #ifdef __REACTOS__
1790 IMEINFOEX info;
1791 size_t cch;
1792
1793 TRACE("ImmGetDescriptionA(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
1794
1795 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_KBDLAYOUT(hKL))
1796 return 0;
1797
1798 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
1799 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
1800 lpszDescription, uBufLen, NULL, NULL);
1801 if (uBufLen)
1802 lpszDescription[cch] = 0;
1803 return cch;
1804 #else
1805 WCHAR *buf;
1806 DWORD len;
1807
1808 TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1809
1810 /* find out how many characters in the unicode buffer */
1811 len = ImmGetDescriptionW( hKL, NULL, 0 );
1812 if (!len)
1813 return 0;
1814
1815 /* allocate a buffer of that size */
1816 buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1817 if( !buf )
1818 return 0;
1819
1820 /* fetch the unicode buffer */
1821 len = ImmGetDescriptionW( hKL, buf, len + 1 );
1822
1823 /* convert it back to ASCII */
1824 len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1825 lpszDescription, uBufLen, NULL, NULL );
1826
1827 HeapFree( GetProcessHeap(), 0, buf );
1828
1829 if (len == 0)
1830 return 0;
1831
1832 return len - 1;
1833 #endif
1834 }
1835
1836 /***********************************************************************
1837 * ImmGetDescriptionW (IMM32.@)
1838 */
1839 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1840 {
1841 #ifdef __REACTOS__
1842 IMEINFOEX info;
1843 size_t cch;
1844
1845 TRACE("ImmGetDescriptionW(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
1846
1847 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_KBDLAYOUT(hKL))
1848 return 0;
1849
1850 if (uBufLen != 0)
1851 StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
1852
1853 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
1854 return (UINT)cch;
1855 #else
1856 static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 };
1857
1858 FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1859
1860 if (!hKL) return 0;
1861 if (!uBufLen) return lstrlenW( name );
1862 lstrcpynW( lpszDescription, name, uBufLen );
1863 return lstrlenW( lpszDescription );
1864 #endif
1865 }
1866
1867 /***********************************************************************
1868 * ImmGetGuideLineA (IMM32.@)
1869 */
1870 DWORD WINAPI ImmGetGuideLineA(
1871 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1872 {
1873 FIXME("(%p, %d, %s, %d): stub\n",
1874 hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1875 );
1876 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1877 return 0;
1878 }
1879
1880 /***********************************************************************
1881 * ImmGetGuideLineW (IMM32.@)
1882 */
1883 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1884 {
1885 FIXME("(%p, %d, %s, %d): stub\n",
1886 hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1887 );
1888 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1889 return 0;
1890 }
1891
1892 /***********************************************************************
1893 * ImmGetIMEFileNameA (IMM32.@)
1894 */
1895 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1896 {
1897 LPWSTR bufW = NULL;
1898 UINT wBufLen = uBufLen;
1899 UINT rc;
1900
1901 if (uBufLen && lpszFileName)
1902 bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1903 else /* We need this to get the number of byte required */
1904 {
1905 bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1906 wBufLen = MAX_PATH;
1907 }
1908
1909 rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1910
1911 if (rc > 0)
1912 {
1913 if (uBufLen && lpszFileName)
1914 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1915 uBufLen, NULL, NULL);
1916 else /* get the length */
1917 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1918 NULL);
1919 }
1920
1921 HeapFree(GetProcessHeap(),0,bufW);
1922 return rc;
1923 }
1924
1925 /***********************************************************************
1926 * ImmGetIMEFileNameW (IMM32.@)
1927 */
1928 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1929 {
1930 HKEY hkey;
1931 DWORD length;
1932 DWORD rc;
1933 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
1934
1935 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
1936 rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1937 if (rc != ERROR_SUCCESS)
1938 {
1939 SetLastError(rc);
1940 return 0;
1941 }
1942
1943 length = 0;
1944 rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length);
1945
1946 if (rc != ERROR_SUCCESS)
1947 {
1948 RegCloseKey(hkey);
1949 SetLastError(rc);
1950 return 0;
1951 }
1952 if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1953 {
1954 RegCloseKey(hkey);
1955 if (lpszFileName)
1956 {
1957 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1958 return 0;
1959 }
1960 else
1961 return length / sizeof(WCHAR);
1962 }
1963
1964 RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1965
1966 RegCloseKey(hkey);
1967
1968 return length / sizeof(WCHAR);
1969 }
1970
1971 /***********************************************************************
1972 * ImmGetOpenStatus (IMM32.@)
1973 */
1974 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1975 {
1976 InputContextData *data = get_imc_data(hIMC);
1977 static int i;
1978
1979 if (!data)
1980 return FALSE;
1981
1982 TRACE("(%p): semi-stub\n", hIMC);
1983
1984 if (!i++)
1985 FIXME("(%p): semi-stub\n", hIMC);
1986
1987 return data->IMC.fOpen;
1988 }
1989
1990 /***********************************************************************
1991 * ImmGetProperty (IMM32.@)
1992 */
1993 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1994 {
1995 DWORD rc = 0;
1996 ImmHkl *kbd;
1997
1998 TRACE("(%p, %d)\n", hKL, fdwIndex);
1999 kbd = IMM_GetImmHkl(hKL);
2000
2001 if (kbd && kbd->hIME)
2002 {
2003 switch (fdwIndex)
2004 {
2005 case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
2006 case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
2007 case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
2008 case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
2009 case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
2010 case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
2011 case IGP_UI: rc = 0; break;
2012 default: rc = 0;
2013 }
2014 }
2015 return rc;
2016 }
2017
2018 /***********************************************************************
2019 * ImmGetRegisterWordStyleA (IMM32.@)
2020 */
2021 UINT WINAPI ImmGetRegisterWordStyleA(
2022 HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
2023 {
2024 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2025 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
2026 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
2027 {
2028 if (!is_kbd_ime_unicode(immHkl))
2029 return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
2030 else
2031 {
2032 STYLEBUFW sbw;
2033 UINT rc;
2034
2035 rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
2036 WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
2037 lpStyleBuf->szDescription, 32, NULL, NULL);
2038 lpStyleBuf->dwStyle = sbw.dwStyle;
2039 return rc;
2040 }
2041 }
2042 else
2043 return 0;
2044 }
2045
2046 /***********************************************************************
2047 * ImmGetRegisterWordStyleW (IMM32.@)
2048 */
2049 UINT WINAPI ImmGetRegisterWordStyleW(
2050 HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
2051 {
2052 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2053 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
2054 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
2055 {
2056 if (is_kbd_ime_unicode(immHkl))
2057 return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
2058 else
2059 {
2060 STYLEBUFA sba;
2061 UINT rc;
2062
2063 rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
2064 MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
2065 lpStyleBuf->szDescription, 32);
2066 lpStyleBuf->dwStyle = sba.dwStyle;
2067 return rc;
2068 }
2069 }
2070 else
2071 return 0;
2072 }
2073
2074 /***********************************************************************
2075 * ImmGetStatusWindowPos (IMM32.@)
2076 */
2077 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2078 {
2079 InputContextData *data = get_imc_data(hIMC);
2080
2081 TRACE("(%p, %p)\n", hIMC, lpptPos);
2082
2083 if (!data || !lpptPos)
2084 return FALSE;
2085
2086 *lpptPos = data->IMC.ptStatusWndPos;
2087
2088 return TRUE;
2089 }
2090
2091 /***********************************************************************
2092 * ImmGetVirtualKey (IMM32.@)
2093 */
2094 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
2095 {
2096 OSVERSIONINFOA version;
2097 InputContextData *data = ImmGetContext( hWnd );
2098 TRACE("%p\n", hWnd);
2099
2100 if ( data )
2101 return data->lastVK;
2102
2103 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2104 GetVersionExA( &version );
2105 switch(version.dwPlatformId)
2106 {
2107 case VER_PLATFORM_WIN32_WINDOWS:
2108 return VK_PROCESSKEY;
2109 case VER_PLATFORM_WIN32_NT:
2110 return 0;
2111 default:
2112 FIXME("%d not supported\n",version.dwPlatformId);
2113 return VK_PROCESSKEY;
2114 }
2115 }
2116
2117 /***********************************************************************
2118 * ImmInstallIMEA (IMM32.@)
2119 */
2120 HKL WINAPI ImmInstallIMEA(
2121 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
2122 {
2123 LPWSTR lpszwIMEFileName;
2124 LPWSTR lpszwLayoutText;
2125 HKL hkl;
2126
2127 TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
2128 debugstr_a(lpszLayoutText));
2129
2130 lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
2131 lpszwLayoutText = strdupAtoW(lpszLayoutText);
2132
2133 hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
2134
2135 HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
2136 HeapFree(GetProcessHeap(),0,lpszwLayoutText);
2137 return hkl;
2138 }
2139
2140 /***********************************************************************
2141 * ImmInstallIMEW (IMM32.@)
2142 */
2143 HKL WINAPI ImmInstallIMEW(
2144 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
2145 {
2146 INT lcid = GetUserDefaultLCID();
2147 INT count;
2148 HKL hkl;
2149 DWORD rc;
2150 HKEY hkey;
2151 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
2152
2153 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
2154 debugstr_w(lpszLayoutText));
2155
2156 /* Start with 2. e001 will be blank and so default to the wine internal IME */
2157 count = 2;
2158
2159 while (count < 0xfff)
2160 {
2161 DWORD disposition = 0;
2162
2163 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
2164 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
2165
2166 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
2167 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
2168 break;
2169 else if (rc == ERROR_SUCCESS)
2170 RegCloseKey(hkey);
2171
2172 count++;
2173 }
2174
2175 if (count == 0xfff)
2176 {
2177 WARN("Unable to find slot to install IME\n");
2178 return 0;
2179 }
2180
2181 if (rc == ERROR_SUCCESS)
2182 {
2183 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
2184 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
2185 if (rc == ERROR_SUCCESS)
2186 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
2187 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
2188 RegCloseKey(hkey);
2189 return hkl;
2190 }
2191 else
2192 {
2193 WARN("Unable to set IME registry values\n");
2194 return 0;
2195 }
2196 }
2197
2198 /***********************************************************************
2199 * ImmIsIME (IMM32.@)
2200 */
2201 BOOL WINAPI ImmIsIME(HKL hKL)
2202 {
2203 ImmHkl *ptr;
2204 TRACE("(%p):\n", hKL);
2205 ptr = IMM_GetImmHkl(hKL);
2206 return (ptr && ptr->hIME);
2207 }
2208
2209 /***********************************************************************
2210 * ImmIsUIMessageA (IMM32.@)
2211 */
2212 BOOL WINAPI ImmIsUIMessageA(
2213 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2214 {
2215 TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2216 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2217 (msg == WM_IME_SETCONTEXT) ||
2218 (msg == WM_IME_NOTIFY) ||
2219 (msg == WM_IME_COMPOSITIONFULL) ||
2220 (msg == WM_IME_SELECT) ||
2221 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2222 {
2223 if (hWndIME)
2224 SendMessageA(hWndIME, msg, wParam, lParam);
2225
2226 return TRUE;
2227 }
2228 return FALSE;
2229 }
2230
2231 /***********************************************************************
2232 * ImmIsUIMessageW (IMM32.@)
2233 */
2234 BOOL WINAPI ImmIsUIMessageW(
2235 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2236 {
2237 TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2238 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2239 (msg == WM_IME_SETCONTEXT) ||
2240 (msg == WM_IME_NOTIFY) ||
2241 (msg == WM_IME_COMPOSITIONFULL) ||
2242 (msg == WM_IME_SELECT) ||
2243 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2244 {
2245 if (hWndIME)
2246 SendMessageW(hWndIME, msg, wParam, lParam);
2247
2248 return TRUE;
2249 }
2250 return FALSE;
2251 }
2252
2253 /***********************************************************************
2254 * ImmNotifyIME (IMM32.@)
2255 */
2256 BOOL WINAPI ImmNotifyIME(
2257 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2258 {
2259 InputContextData *data = get_imc_data(hIMC);
2260
2261 TRACE("(%p, %d, %d, %d)\n",
2262 hIMC, dwAction, dwIndex, dwValue);
2263
2264 if (hIMC == NULL)
2265 {
2266 SetLastError(ERROR_SUCCESS);
2267 return FALSE;
2268 }
2269
2270 if (!data || ! data->immKbd->pNotifyIME)
2271 {
2272 return FALSE;
2273 }
2274
2275 return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
2276 }
2277
2278 /***********************************************************************
2279 * ImmRegisterWordA (IMM32.@)
2280 */
2281 BOOL WINAPI ImmRegisterWordA(
2282 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
2283 {
2284 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2285 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2286 debugstr_a(lpszRegister));
2287 if (immHkl->hIME && immHkl->pImeRegisterWord)
2288 {
2289 if (!is_kbd_ime_unicode(immHkl))
2290 return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
2291 (LPCWSTR)lpszRegister);
2292 else
2293 {
2294 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2295 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
2296 BOOL rc;
2297
2298 rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
2299 HeapFree(GetProcessHeap(),0,lpszwReading);
2300 HeapFree(GetProcessHeap(),0,lpszwRegister);
2301 return rc;
2302 }
2303 }
2304 else
2305 return FALSE;
2306 }
2307
2308 /***********************************************************************
2309 * ImmRegisterWordW (IMM32.@)
2310 */
2311 BOOL WINAPI ImmRegisterWordW(
2312 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
2313 {
2314 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2315 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2316 debugstr_w(lpszRegister));
2317 if (immHkl->hIME && immHkl->pImeRegisterWord)
2318 {
2319 if (is_kbd_ime_unicode(immHkl))
2320 return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
2321 else
2322 {
2323 LPSTR lpszaReading = strdupWtoA(lpszReading);
2324 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
2325 BOOL rc;
2326
2327 rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
2328 (LPCWSTR)lpszaRegister);
2329 HeapFree(GetProcessHeap(),0,lpszaReading);
2330 HeapFree(GetProcessHeap(),0,lpszaRegister);
2331 return rc;
2332 }
2333 }
2334 else
2335 return FALSE;
2336 }
2337
2338 /***********************************************************************
2339 * ImmReleaseContext (IMM32.@)
2340 */
2341 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2342 {
2343 static BOOL shown = FALSE;
2344
2345 if (!shown) {
2346 FIXME("(%p, %p): stub\n", hWnd, hIMC);
2347 shown = TRUE;
2348 }
2349 return TRUE;
2350 }
2351
2352 /***********************************************************************
2353 * ImmRequestMessageA(IMM32.@)
2354 */
2355 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2356 {
2357 InputContextData *data = get_imc_data(hIMC);
2358
2359 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2360
2361 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2362
2363 SetLastError(ERROR_INVALID_HANDLE);
2364 return 0;
2365 }
2366
2367 /***********************************************************************
2368 * ImmRequestMessageW(IMM32.@)
2369 */
2370 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2371 {
2372 InputContextData *data = get_imc_data(hIMC);
2373
2374 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2375
2376 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2377
2378 SetLastError(ERROR_INVALID_HANDLE);
2379 return 0;
2380 }
2381
2382 /***********************************************************************
2383 * ImmSetCandidateWindow (IMM32.@)
2384 */
2385 BOOL WINAPI ImmSetCandidateWindow(
2386 HIMC hIMC, LPCANDIDATEFORM lpCandidate)
2387 {
2388 InputContextData *data = get_imc_data(hIMC);
2389
2390 TRACE("(%p, %p)\n", hIMC, lpCandidate);
2391
2392 if (!data || !lpCandidate)
2393 return FALSE;
2394
2395 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2396 return FALSE;
2397
2398 TRACE("\t%x, %x, %s, %s\n",
2399 lpCandidate->dwIndex, lpCandidate->dwStyle,
2400 wine_dbgstr_point(&lpCandidate->ptCurrentPos),
2401 wine_dbgstr_rect(&lpCandidate->rcArea));
2402
2403 if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
2404 return FALSE;
2405
2406 data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
2407 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
2408 ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
2409
2410 return TRUE;
2411 }
2412
2413 /***********************************************************************
2414 * ImmSetCompositionFontA (IMM32.@)
2415 */
2416 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
2417 {
2418 InputContextData *data = get_imc_data(hIMC);
2419 TRACE("(%p, %p)\n", hIMC, lplf);
2420
2421 if (!data || !lplf)
2422 {
2423 SetLastError(ERROR_INVALID_HANDLE);
2424 return FALSE;
2425 }
2426
2427 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2428 return FALSE;
2429
2430 memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
2431 MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
2432 LF_FACESIZE);
2433 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2434 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2435
2436 return TRUE;
2437 }
2438
2439 /***********************************************************************
2440 * ImmSetCompositionFontW (IMM32.@)
2441 */
2442 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
2443 {
2444 InputContextData *data = get_imc_data(hIMC);
2445 TRACE("(%p, %p)\n", hIMC, lplf);
2446
2447 if (!data || !lplf)
2448 {
2449 SetLastError(ERROR_INVALID_HANDLE);
2450 return FALSE;
2451 }
2452
2453 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2454 return FALSE;
2455
2456 data->IMC.lfFont.W = *lplf;
2457 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2458 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2459
2460 return TRUE;
2461 }
2462
2463 /***********************************************************************
2464 * ImmSetCompositionStringA (IMM32.@)
2465 */
2466 BOOL WINAPI ImmSetCompositionStringA(
2467 HIMC hIMC, DWORD dwIndex,
2468 LPCVOID lpComp, DWORD dwCompLen,
2469 LPCVOID lpRead, DWORD dwReadLen)
2470 {
2471 DWORD comp_len;
2472 DWORD read_len;
2473 WCHAR *CompBuffer = NULL;
2474 WCHAR *ReadBuffer = NULL;
2475 BOOL rc;
2476 InputContextData *data = get_imc_data(hIMC);
2477
2478 TRACE("(%p, %d, %p, %d, %p, %d):\n",
2479 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2480
2481 if (!data)
2482 return FALSE;
2483
2484 if (!(dwIndex == SCS_SETSTR ||
2485 dwIndex == SCS_CHANGEATTR ||
2486 dwIndex == SCS_CHANGECLAUSE ||
2487 dwIndex == SCS_SETRECONVERTSTRING ||
2488 dwIndex == SCS_QUERYRECONVERTSTRING))
2489 return FALSE;
2490
2491 if (!is_himc_ime_unicode(data))
2492 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2493 dwCompLen, lpRead, dwReadLen);
2494
2495 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2496 if (comp_len)
2497 {
2498 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2499 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2500 }
2501
2502 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2503 if (read_len)
2504 {
2505 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2506 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2507 }
2508
2509 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2510 ReadBuffer, read_len);
2511
2512 HeapFree(GetProcessHeap(), 0, CompBuffer);
2513 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2514
2515 return rc;
2516 }
2517
2518 /***********************************************************************
2519 * ImmSetCompositionStringW (IMM32.@)
2520 */
2521 BOOL WINAPI ImmSetCompositionStringW(
2522 HIMC hIMC, DWORD dwIndex,
2523 LPCVOID lpComp, DWORD dwCompLen,
2524 LPCVOID lpRead, DWORD dwReadLen)
2525 {
2526 DWORD comp_len;
2527 DWORD read_len;
2528 CHAR *CompBuffer = NULL;
2529 CHAR *ReadBuffer = NULL;
2530 BOOL rc;
2531 InputContextData *data = get_imc_data(hIMC);
2532
2533 TRACE("(%p, %d, %p, %d, %p, %d):\n",
2534 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2535
2536 if (!data)
2537 return FALSE;
2538
2539 if (!(dwIndex == SCS_SETSTR ||
2540 dwIndex == SCS_CHANGEATTR ||
2541 dwIndex == SCS_CHANGECLAUSE ||
2542 dwIndex == SCS_SETRECONVERTSTRING ||
2543 dwIndex == SCS_QUERYRECONVERTSTRING))
2544 return FALSE;
2545
2546 if (is_himc_ime_unicode(data))
2547 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2548 dwCompLen, lpRead, dwReadLen);
2549
2550 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2551 NULL);
2552 if (comp_len)
2553 {
2554 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
2555 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2556 NULL, NULL);
2557 }
2558
2559 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2560 NULL);
2561 if (read_len)
2562 {
2563 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
2564 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2565 NULL, NULL);
2566 }
2567
2568 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2569 ReadBuffer, read_len);
2570
2571 HeapFree(GetProcessHeap(), 0, CompBuffer);
2572 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2573
2574 return rc;
2575 }
2576
2577 /***********************************************************************
2578 * ImmSetCompositionWindow (IMM32.@)
2579 */
2580 BOOL WINAPI ImmSetCompositionWindow(
2581 HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2582 {
2583 BOOL reshow = FALSE;
2584 InputContextData *data = get_imc_data(hIMC);
2585
2586 TRACE("(%p, %p)\n", hIMC, lpCompForm);
2587 if (lpCompForm)
2588 TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle,
2589 wine_dbgstr_point(&lpCompForm->ptCurrentPos),
2590 wine_dbgstr_rect(&lpCompForm->rcArea));
2591
2592 if (!data)
2593 {
2594 SetLastError(ERROR_INVALID_HANDLE);
2595 return FALSE;
2596 }
2597
2598 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2599 return FALSE;
2600
2601 data->IMC.cfCompForm = *lpCompForm;
2602
2603 if (IsWindowVisible(data->immKbd->UIWnd))
2604 {
2605 reshow = TRUE;
2606 ShowWindow(data->immKbd->UIWnd,SW_HIDE);
2607 }
2608
2609 /* FIXME: this is a partial stub */
2610
2611 if (reshow)
2612 ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
2613
2614 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2615 return TRUE;
2616 }
2617
2618 /***********************************************************************
2619 * ImmSetConversionStatus (IMM32.@)
2620 */
2621 BOOL WINAPI ImmSetConversionStatus(
2622 HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2623 {
2624 DWORD oldConversion, oldSentence;
2625 InputContextData *data = get_imc_data(hIMC);
2626
2627 TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
2628
2629 if (!data)
2630 {
2631 SetLastError(ERROR_INVALID_HANDLE);
2632 return FALSE;
2633 }
2634
2635 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2636 return FALSE;
2637
2638 if ( fdwConversion != data->IMC.fdwConversion )
2639 {
2640 oldConversion = data->IMC.fdwConversion;
2641 data->IMC.fdwConversion = fdwConversion;
2642 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
2643 ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
2644 }
2645 if ( fdwSentence != data->IMC.fdwSentence )
2646 {
2647 oldSentence = data->IMC.fdwSentence;
2648 data->IMC.fdwSentence = fdwSentence;
2649 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
2650 ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
2651 }
2652
2653 return TRUE;
2654 }
2655
2656 /***********************************************************************
2657 * ImmSetOpenStatus (IMM32.@)
2658 */
2659 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2660 {
2661 InputContextData *data = get_imc_data(hIMC);
2662
2663 TRACE("%p %d\n", hIMC, fOpen);
2664
2665 if (!data)
2666 {
2667 SetLastError(ERROR_INVALID_HANDLE);
2668 return FALSE;
2669 }
2670
2671 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2672 return FALSE;
2673
2674 if (data->immKbd->UIWnd == NULL)
2675 {
2676 /* create the ime window */
2677 data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
2678 data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
2679 0, data->immKbd->hIME, 0);
2680 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2681 }
2682 else if (fOpen)
2683 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2684
2685 if (!fOpen != !data->IMC.fOpen)
2686 {
2687 data->IMC.fOpen = fOpen;
2688 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
2689 ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
2690 }
2691
2692 return TRUE;
2693 }
2694
2695 /***********************************************************************
2696 * ImmSetStatusWindowPos (IMM32.@)
2697 */
2698 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2699 {
2700 InputContextData *data = get_imc_data(hIMC);
2701
2702 TRACE("(%p, %p)\n", hIMC, lpptPos);
2703
2704 if (!data || !lpptPos)
2705 {
2706 SetLastError(ERROR_INVALID_HANDLE);
2707 return FALSE;
2708 }
2709
2710 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2711 return FALSE;
2712
2713 TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
2714
2715 data->IMC.ptStatusWndPos = *lpptPos;
2716 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
2717 ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
2718
2719 return TRUE;
2720 }
2721
2722 /***********************************************************************
2723 * ImmCreateSoftKeyboard(IMM32.@)
2724 */
2725 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2726 {
2727 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2728 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2729 return 0;
2730 }
2731
2732 /***********************************************************************
2733 * ImmDestroySoftKeyboard(IMM32.@)
2734 */
2735 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2736 {
2737 #ifdef __REACTOS__
2738 TRACE("(%p)\n", hSoftWnd);
2739 return DestroyWindow(hSoftWnd);
2740 #else
2741 FIXME("(%p): stub\n", hSoftWnd);
2742 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2743 return FALSE;
2744 #endif
2745 }
2746
2747 /***********************************************************************
2748 * ImmShowSoftKeyboard(IMM32.@)
2749 */
2750 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2751 {
2752 #ifdef __REACTOS__
2753 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
2754 if (hSoftWnd)
2755 return ShowWindow(hSoftWnd, nCmdShow);
2756 #else
2757 FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2758 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2759 #endif
2760 return FALSE;
2761 }
2762
2763 /***********************************************************************
2764 * ImmSimulateHotKey (IMM32.@)
2765 */
2766 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2767 {
2768 FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
2769 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2770 return FALSE;
2771 }
2772
2773 /***********************************************************************
2774 * ImmUnregisterWordA (IMM32.@)
2775 */
2776 BOOL WINAPI ImmUnregisterWordA(
2777 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2778 {
2779 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2780 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2781 debugstr_a(lpszUnregister));
2782 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2783 {
2784 if (!is_kbd_ime_unicode(immHkl))
2785 return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
2786 (LPCWSTR)lpszUnregister);
2787 else
2788 {
2789 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2790 LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
2791 BOOL rc;
2792
2793 rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
2794 HeapFree(GetProcessHeap(),0,lpszwReading);
2795 HeapFree(GetProcessHeap(),0,lpszwUnregister);
2796 return rc;
2797 }
2798 }
2799 else
2800 return FALSE;
2801 }
2802
2803 /***********************************************************************
2804 * ImmUnregisterWordW (IMM32.@)
2805 */
2806 BOOL WINAPI ImmUnregisterWordW(
2807 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2808 {
2809 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2810 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2811 debugstr_w(lpszUnregister));
2812 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2813 {
2814 if (is_kbd_ime_unicode(immHkl))
2815 return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
2816 else
2817 {
2818 LPSTR lpszaReading = strdupWtoA(lpszReading);
2819 LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
2820 BOOL rc;
2821
2822 rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
2823 (LPCWSTR)lpszaUnregister);
2824 HeapFree(GetProcessHeap(),0,lpszaReading);
2825 HeapFree(GetProcessHeap(),0,lpszaUnregister);
2826 return rc;
2827 }
2828 }
2829 else
2830 return FALSE;
2831 }
2832
2833 /***********************************************************************
2834 * ImmGetImeMenuItemsA (IMM32.@)
2835 */
2836 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2837 LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2838 DWORD dwSize)
2839 {
2840 InputContextData *data = get_imc_data(hIMC);
2841 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2842 lpImeParentMenu, lpImeMenu, dwSize);
2843
2844 if (!data)
2845 {
2846 SetLastError(ERROR_INVALID_HANDLE);
2847 return 0;
2848 }
2849
2850 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2851 {
2852 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2853 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2854 (IMEMENUITEMINFOW*)lpImeParentMenu,
2855 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2856 else
2857 {
2858 IMEMENUITEMINFOW lpImeParentMenuW;
2859 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2860 DWORD rc;
2861
2862 if (lpImeParentMenu)
2863 parent = &lpImeParentMenuW;
2864 if (lpImeMenu)
2865 {
2866 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2867 dwSize = count * sizeof(IMEMENUITEMINFOW);
2868 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2869 }
2870 else
2871 lpImeMenuW = NULL;
2872
2873 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2874 parent, lpImeMenuW, dwSize);
2875
2876 if (lpImeParentMenu)
2877 {
2878 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2879 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2880 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2881 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2882 NULL, NULL);
2883 }
2884 if (lpImeMenu && rc)
2885 {
2886 unsigned int i;
2887 for (i = 0; i < rc; i++)
2888 {
2889 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2890 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2891 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2892 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2893 NULL, NULL);
2894 }
2895 }
2896 HeapFree(GetProcessHeap(),0,lpImeMenuW);
2897 return rc;
2898 }
2899 }
2900 else
2901 return 0;
2902 }
2903
2904 /***********************************************************************
2905 * ImmGetImeMenuItemsW (IMM32.@)
2906 */
2907 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2908 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2909 DWORD dwSize)
2910 {
2911 InputContextData *data = get_imc_data(hIMC);
2912 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2913 lpImeParentMenu, lpImeMenu, dwSize);
2914
2915 if (!data)
2916 {
2917 SetLastError(ERROR_INVALID_HANDLE);
2918 return 0;
2919 }
2920
2921 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2922 {
2923 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2924 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2925 lpImeParentMenu, lpImeMenu, dwSize);
2926 else
2927 {
2928 IMEMENUITEMINFOA lpImeParentMenuA;
2929 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2930 DWORD rc;
2931
2932 if (lpImeParentMenu)
2933 parent = &lpImeParentMenuA;
2934 if (lpImeMenu)
2935 {
2936 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2937 dwSize = count * sizeof(IMEMENUITEMINFOA);
2938 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2939 }
2940 else
2941 lpImeMenuA = NULL;
2942
2943 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2944 (IMEMENUITEMINFOW*)parent,
2945 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2946
2947 if (lpImeParentMenu)
2948 {
2949 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2950 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2951 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2952 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2953 }
2954 if (lpImeMenu && rc)
2955 {
2956 unsigned int i;
2957 for (i = 0; i < rc; i++)
2958 {
2959 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2960 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2961 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2962 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2963 }
2964 }
2965 HeapFree(GetProcessHeap(),0,lpImeMenuA);
2966 return rc;
2967 }
2968 }
2969 else
2970 return 0;
2971 }
2972
2973 /***********************************************************************
2974 * ImmLockIMC(IMM32.@)
2975 */
2976 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2977 {
2978 InputContextData *data = get_imc_data(hIMC);
2979
2980 if (!data)
2981 return NULL;
2982 data->dwLock++;
2983 return &data->IMC;
2984 }
2985
2986 /***********************************************************************
2987 * ImmUnlockIMC(IMM32.@)
2988 */
2989 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2990 {
2991 InputContextData *data = get_imc_data(hIMC);
2992
2993 if (!data)
2994 return FALSE;
2995 if (data->dwLock)
2996 data->dwLock--;
2997 return TRUE;
2998 }
2999
3000 /***********************************************************************
3001 * ImmGetIMCLockCount(IMM32.@)
3002 */
3003 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
3004 {
3005 InputContextData *data = get_imc_data(hIMC);
3006 if (!data)
3007 return 0;
3008 return data->dwLock;
3009 }
3010
3011 /***********************************************************************
3012 * ImmCreateIMCC(IMM32.@)
3013 */
3014 HIMCC WINAPI ImmCreateIMCC(DWORD size)
3015 {
3016 #ifdef __REACTOS__
3017 if (size < 4)
3018 size = 4;
3019 return LocalAlloc(LHND, size);
3020 #else
3021 return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
3022 #endif
3023 }
3024
3025 /***********************************************************************
3026 * ImmDestroyIMCC(IMM32.@)
3027 */
3028 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
3029 {
3030 #ifdef __REACTOS__
3031 if (block)
3032 return LocalFree(block);
3033 return NULL;
3034 #else
3035 return GlobalFree(block);
3036 #endif
3037 }
3038
3039 /***********************************************************************
3040 * ImmLockIMCC(IMM32.@)
3041 */
3042 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
3043 {
3044 #ifdef __REACTOS__
3045 if (imcc)
3046 return LocalLock(imcc);
3047 return NULL;
3048 #else
3049 return GlobalLock(imcc);
3050 #endif
3051 }
3052
3053 /***********************************************************************
3054 * ImmUnlockIMCC(IMM32.@)
3055 */
3056 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
3057 {
3058 #ifdef __REACTOS__
3059 if (imcc)
3060 return LocalUnlock(imcc);
3061 return FALSE;
3062 #else
3063 return GlobalUnlock(imcc);
3064 #endif
3065 }
3066
3067 /***********************************************************************
3068 * ImmGetIMCCLockCount(IMM32.@)
3069 */
3070 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
3071 {
3072 #ifdef __REACTOS__
3073 return LocalFlags(imcc) & LMEM_LOCKCOUNT;
3074 #else
3075 return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
3076 #endif
3077 }
3078
3079 /***********************************************************************
3080 * ImmReSizeIMCC(IMM32.@)
3081 */
3082 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
3083 {
3084 #ifdef __REACTOS__
3085 if (!imcc)
3086 return NULL;
3087 return LocalReAlloc(imcc, size, LHND);
3088 #else
3089 return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
3090 #endif
3091 }
3092
3093 /***********************************************************************
3094 * ImmGetIMCCSize(IMM32.@)
3095 */
3096 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
3097 {
3098 #ifdef __REACTOS__
3099 if (imcc)
3100 return LocalSize(imcc);
3101 return 0;
3102 #else
3103 return GlobalSize(imcc);
3104 #endif
3105 }
3106
3107 /***********************************************************************
3108 * ImmGenerateMessage(IMM32.@)
3109 */
3110 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
3111 {
3112 InputContextData *data = get_imc_data(hIMC);
3113
3114 if (!data)
3115 {
3116 SetLastError(ERROR_INVALID_HANDLE);
3117 return FALSE;
3118 }
3119
3120 TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
3121 if (data->IMC.dwNumMsgBuf > 0)
3122 {
3123 LPTRANSMSG lpTransMsg;
3124 HIMCC hMsgBuf;
3125 DWORD i, dwNumMsgBuf;
3126
3127 /* We are going to detach our hMsgBuff so that if processing messages
3128 generates new messages they go into a new buffer */
3129 hMsgBuf = data->IMC.hMsgBuf;
3130 dwNumMsgBuf = data->IMC.dwNumMsgBuf;
3131
3132 data->IMC.hMsgBuf = ImmCreateIMCC(0);
3133 data->IMC.dwNumMsgBuf = 0;
3134
3135 lpTransMsg = ImmLockIMCC(hMsgBuf);
3136 for (i = 0; i < dwNumMsgBuf; i++)
3137 ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
3138
3139 ImmUnlockIMCC(hMsgBuf);
3140 ImmDestroyIMCC(hMsgBuf);
3141 }
3142
3143 return TRUE;
3144 }
3145
3146 /***********************************************************************
3147 * ImmTranslateMessage(IMM32.@)
3148 * ( Undocumented, call internally and from user32.dll )
3149 */
3150 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
3151 {
3152 InputContextData *data;
3153 HIMC imc = ImmGetContext(hwnd);
3154 BYTE state[256];
3155 UINT scancode;
3156 LPVOID list = 0;
3157 UINT msg_count;
3158 UINT uVirtKey;
3159 static const DWORD list_count = 10;
3160
3161 TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
3162
3163 if (imc)
3164 data = imc;
3165 else
3166 return FALSE;
3167
3168 if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
3169 return FALSE;
3170
3171 GetKeyboardState(state);
3172 scancode = lKeyData >> 0x10 & 0xff;
3173
3174 list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
3175 ((DWORD*)list)[0] = list_count;
3176
3177 if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3178 {
3179 WCHAR chr;
3180
3181 if (!is_himc_ime_unicode(data))
3182 ToAscii(data->lastVK, scancode, state, &chr, 0);
3183 else
3184 ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
3185 uVirtKey = MAKELONG(data->lastVK,chr);
3186 }
3187 else
3188 uVirtKey = data->lastVK;
3189
3190 msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
3191 TRACE("%i messages generated\n",msg_count);
3192 if (msg_count && msg_count <= list_count)
3193 {
3194 UINT i;
3195 LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
3196
3197 for (i = 0; i < msg_count; i++)
3198 ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
3199 }
3200 else if (msg_count > list_count)
3201 ImmGenerateMessage(imc);
3202
3203 HeapFree(GetProcessHeap(),0,list);
3204
3205 data->lastVK = VK_PROCESSKEY;
3206
3207 return (msg_count > 0);
3208 }
3209
3210 /***********************************************************************
3211 * ImmProcessKey(IMM32.@)
3212 * ( Undocumented, called from user32.dll )
3213 */
3214 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
3215 {
3216 InputContextData *data;
3217 HIMC imc = ImmGetContext(hwnd);
3218 BYTE state[256];
3219
3220 TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
3221
3222 if (imc)
3223 data = imc;
3224 else
3225 return FALSE;
3226
3227 /* Make sure we are inputting to the correct keyboard */
3228 if (data->immKbd->hkl != hKL)
3229 {
3230 ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
3231 if (new_hkl)
3232 {
3233 data->immKbd->pImeSelect(imc, FALSE);
3234 data->immKbd->uSelected--;
3235 data->immKbd = new_hkl;
3236 data->immKbd->pImeSelect(imc, TRUE);
3237 data->immKbd->uSelected++;
3238 }
3239 else
3240 return FALSE;
3241 }
3242
3243 if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
3244 return FALSE;
3245
3246 GetKeyboardState(state);
3247 if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
3248 {
3249 data->lastVK = vKey;
3250 return TRUE;
3251 }
3252
3253 data->lastVK = VK_PROCESSKEY;
3254 return FALSE;
3255 }
3256
3257 /***********************************************************************
3258 * ImmDisableTextFrameService(IMM32.@)
3259 */
3260 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3261 {
3262 FIXME("Stub\n");
3263 return FALSE;
3264 }
3265
3266 /***********************************************************************
3267 * ImmEnumInputContext(IMM32.@)
3268 */
3269
3270 BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
3271 {
3272 FIXME("Stub\n");
3273 return FALSE;
3274 }
3275
3276 /***********************************************************************
3277 * ImmGetHotKey(IMM32.@)
3278 */
3279
3280 #ifdef __REACTOS__
3281 BOOL WINAPI
3282 ImmGetHotKey(IN DWORD dwHotKey,
3283 OUT LPUINT lpuModifiers,
3284 OUT LPUINT lpuVKey,
3285 OUT LPHKL lphKL)
3286 {
3287 TRACE("%lx, %p, %p, %p\n", dwHotKey, lpuModifiers, lpuVKey, lphKL);
3288 if (lpuModifiers && lpuVKey)
3289 return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL);
3290 return FALSE;
3291 }
3292 #else
3293 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
3294 {
3295 FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3296 return FALSE;
3297 }
3298 #endif
3299
3300 /***********************************************************************
3301 * ImmDisableLegacyIME(IMM32.@)
3302 */
3303 BOOL WINAPI ImmDisableLegacyIME(void)
3304 {
3305 FIXME("stub\n");
3306 return TRUE;
3307 }
3308
3309 #ifdef __REACTOS__
3310 /***********************************************************************
3311 * ImmSetActiveContext(IMM32.@)
3312 */
3313 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag)
3314 {
3315 FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag);
3316 return FALSE;
3317 }
3318
3319 /***********************************************************************
3320 * ImmSetActiveContextConsoleIME(IMM32.@)
3321 */
3322 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
3323 {
3324 HIMC hIMC;
3325 TRACE("(%p, %d)\n", hwnd, fFlag);
3326
3327 hIMC = ImmGetContext(hwnd);
3328 if (hIMC)
3329 return ImmSetActiveContext(hwnd, hIMC, fFlag);
3330 return FALSE;
3331 }
3332
3333 /***********************************************************************
3334 * ImmRegisterClient(IMM32.@)
3335 * ( Undocumented, called from user32.dll )
3336 */
3337 BOOL WINAPI ImmRegisterClient(PVOID ptr, /* FIXME: should point to SHAREDINFO structure */
3338 HINSTANCE hMod)
3339 {
3340 FIXME("Stub\n");
3341 return TRUE;
3342 }
3343
3344 /***********************************************************************
3345 * ImmGetImeInfoEx (IMM32.@)
3346 */
3347 BOOL WINAPI
3348 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx,
3349 IMEINFOEXCLASS SearchType,
3350 PVOID pvSearchKey)
3351 {
3352 switch (SearchType)
3353 {
3354 case ImeInfoExKeyboardLayout:
3355 pImeInfoEx->hkl = *(LPHKL)pvSearchKey;
3356 if (!IS_IME_HKL(pImeInfoEx->hkl))
3357 return FALSE;
3358 break;
3359
3360 case ImeInfoExImeFileName:
3361 lstrcpynW(pImeInfoEx->wszImeFile, (LPWSTR)pvSearchKey,
3362 ARRAY_SIZE(pImeInfoEx->wszImeFile));
3363 break;
3364
3365 default:
3366 return FALSE;
3367 }
3368 return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
3369 }
3370 #endif