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