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