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