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