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