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