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