3edb95b08ef3bb48bc72a69c296f9032323823f4
[reactos.git] / dll / win32 / imm32 / ime.c
1 /*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing IME manipulation of IMM32
5 * COPYRIGHT: Copyright 1998 Patrik Stridvall
6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * Copyright 2017 James Tabor <james.tabor@reactos.org>
8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9 * Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
11 */
12
13 #include "precomp.h"
14
15 WINE_DEFAULT_DEBUG_CHANNEL(imm);
16
17 RTL_CRITICAL_SECTION g_csImeDpi;
18 PIMEDPI g_pImeDpiList = NULL;
19
20 PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL)
21 {
22 PIMEDPI pImeDpi;
23
24 RtlEnterCriticalSection(&g_csImeDpi);
25 for (pImeDpi = g_pImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext)
26 {
27 if (pImeDpi->hKL == hKL)
28 break;
29 }
30 RtlLeaveCriticalSection(&g_csImeDpi);
31
32 return pImeDpi;
33 }
34
35 VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy)
36 {
37 if (pImeDpi->hInst == NULL)
38 return;
39 if (bDestroy)
40 pImeDpi->ImeDestroy(0);
41 FreeLibrary(pImeDpi->hInst);
42 pImeDpi->hInst = NULL;
43 }
44
45 BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi)
46 {
47 WCHAR szUIClass[64];
48 WNDCLASSW wcW;
49 DWORD dwSysInfoFlags = 0; // TODO: ???
50 LPIMEINFO pImeInfo = &pImeDpi->ImeInfo;
51
52 // TODO: NtUserGetThreadState(16);
53
54 if (!IS_IME_HKL(pImeDpi->hKL))
55 {
56 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) &&
57 pImeDpi->CtfImeInquireExW)
58 {
59 // TODO:
60 return FALSE;
61 }
62 }
63
64 if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags))
65 return FALSE;
66
67 szUIClass[_countof(szUIClass) - 1] = 0;
68
69 if (pImeInfo->dwPrivateDataSize == 0)
70 pImeInfo->dwPrivateDataSize = 4;
71
72 #define VALID_IME_PROP (IME_PROP_AT_CARET | \
73 IME_PROP_SPECIAL_UI | \
74 IME_PROP_CANDLIST_START_FROM_1 | \
75 IME_PROP_UNICODE | \
76 IME_PROP_COMPLETE_ON_UNSELECT | \
77 IME_PROP_END_UNLOAD | \
78 IME_PROP_KBD_CHAR_FIRST | \
79 IME_PROP_IGNORE_UPKEYS | \
80 IME_PROP_NEED_ALTKEY | \
81 IME_PROP_NO_KEYS_ON_CLOSE | \
82 IME_PROP_ACCEPT_WIDE_VKEY)
83 #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \
84 IME_CMODE_NATIVE | \
85 IME_CMODE_KATAKANA | \
86 IME_CMODE_LANGUAGE | \
87 IME_CMODE_FULLSHAPE | \
88 IME_CMODE_ROMAN | \
89 IME_CMODE_CHARCODE | \
90 IME_CMODE_HANJACONVERT | \
91 IME_CMODE_SOFTKBD | \
92 IME_CMODE_NOCONVERSION | \
93 IME_CMODE_EUDC | \
94 IME_CMODE_SYMBOL | \
95 IME_CMODE_FIXED)
96 #define VALID_SMODE_CAPS (IME_SMODE_NONE | \
97 IME_SMODE_PLAURALCLAUSE | \
98 IME_SMODE_SINGLECONVERT | \
99 IME_SMODE_AUTOMATIC | \
100 IME_SMODE_PHRASEPREDICT | \
101 IME_SMODE_CONVERSATION)
102 #define VALID_UI_CAPS (UI_CAP_2700 | \
103 UI_CAP_ROT90 | \
104 UI_CAP_ROTANY | \
105 UI_CAP_SOFTKBD)
106 #define VALID_SCS_CAPS (SCS_CAP_COMPSTR | \
107 SCS_CAP_MAKEREAD | \
108 SCS_CAP_SETRECONVERTSTRING)
109 #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE)
110
111 if (pImeInfo->fdwProperty & ~VALID_IME_PROP)
112 return FALSE;
113 if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS)
114 return FALSE;
115 if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS)
116 return FALSE;
117 if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS)
118 return FALSE;
119 if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS)
120 return FALSE;
121 if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS)
122 return FALSE;
123
124 #undef VALID_IME_PROP
125 #undef VALID_CMODE_CAPS
126 #undef VALID_SMODE_CAPS
127 #undef VALID_UI_CAPS
128 #undef VALID_SCS_CAPS
129 #undef VALID_SELECT_CAPS
130
131 if (pImeInfo->fdwProperty & IME_PROP_UNICODE)
132 {
133 StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass);
134 }
135 else
136 {
137 if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage)
138 return FALSE;
139
140 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1,
141 pImeDpi->szUIClass, _countof(pImeDpi->szUIClass));
142 }
143
144 return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW);
145 }
146
147 BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
148 {
149 WCHAR szPath[MAX_PATH];
150 HINSTANCE hIME;
151 FARPROC fn;
152
153 if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
154 return FALSE;
155
156 hIME = GetModuleHandleW(szPath);
157 if (hIME == NULL)
158 {
159 hIME = LoadLibraryW(szPath);
160 if (hIME == NULL)
161 {
162 ERR("Imm32LoadImeInfo: LoadLibraryW(%S) failed\n", szPath);
163 return FALSE;
164 }
165 }
166 pImeDpi->hInst = hIME;
167
168 #define DEFINE_IME_ENTRY(type, name, params, extended) \
169 do { \
170 fn = GetProcAddress(hIME, #name); \
171 if (fn) pImeDpi->name = (FN_##name)fn; \
172 else if (!extended) goto Failed; \
173 } while (0);
174 #include "../../../win32ss/include/imetable.h"
175 #undef DEFINE_IME_ENTRY
176
177 if (!Imm32InquireIme(pImeDpi))
178 {
179 ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n");
180 goto Failed;
181 }
182
183 if (pImeInfoEx->fLoadFlag)
184 return TRUE;
185
186 NtUserSetImeOwnerWindow(pImeInfoEx, TRUE);
187 return TRUE;
188
189 Failed:
190 FreeLibrary(pImeDpi->hInst);
191 pImeDpi->hInst = NULL;
192 return FALSE;
193 }
194
195 PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock)
196 {
197 IMEINFOEX ImeInfoEx;
198 CHARSETINFO ci;
199 PIMEDPI pImeDpiNew, pImeDpiFound;
200 UINT uCodePage;
201 LCID lcid;
202
203 if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) ||
204 ImeInfoEx.fLoadFlag == 1)
205 {
206 return NULL;
207 }
208
209 pImeDpiNew = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI));
210 if (pImeDpiNew == NULL)
211 return NULL;
212
213 pImeDpiNew->hKL = hKL;
214
215 lcid = LOWORD(hKL);
216 if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE))
217 uCodePage = ci.ciACP;
218 else
219 uCodePage = CP_ACP;
220 pImeDpiNew->uCodePage = uCodePage;
221
222 if (!Imm32LoadImeInfo(&ImeInfoEx, pImeDpiNew))
223 {
224 HeapFree(g_hImm32Heap, 0, pImeDpiNew);
225 return FALSE;
226 }
227
228 RtlEnterCriticalSection(&g_csImeDpi);
229
230 pImeDpiFound = Imm32FindImeDpi(hKL);
231 if (pImeDpiFound)
232 {
233 if (!bLock)
234 pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED;
235
236 RtlLeaveCriticalSection(&g_csImeDpi);
237
238 Imm32FreeImeDpi(pImeDpiNew, FALSE);
239 HeapFree(g_hImm32Heap, 0, pImeDpiNew);
240 return pImeDpiFound;
241 }
242 else
243 {
244 if (bLock)
245 {
246 pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED;
247 pImeDpiNew->cLockObj = 1;
248 }
249
250 pImeDpiNew->pNext = g_pImeDpiList;
251 g_pImeDpiList = pImeDpiNew;
252
253 RtlLeaveCriticalSection(&g_csImeDpi);
254 return pImeDpiNew;
255 }
256 }
257
258 PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL)
259 {
260 PW32CLIENTINFO pInfo;
261 PIMEDPI pImeDpi;
262
263 if (!IS_IME_HKL(hKL))
264 {
265 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
266 return NULL;
267
268 pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo);
269 if ((pInfo->W32ClientInfo[0] & 2))
270 return NULL;
271 }
272
273 pImeDpi = ImmLockImeDpi(hKL);
274 if (pImeDpi == NULL)
275 pImeDpi = Ime32LoadImeDpi(hKL, TRUE);
276 return pImeDpi;
277 }
278
279 /***********************************************************************
280 * ImmIsIME (IMM32.@)
281 */
282 BOOL WINAPI ImmIsIME(HKL hKL)
283 {
284 IMEINFOEX info;
285 TRACE("(%p)\n", hKL);
286 return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL);
287 }
288
289 /***********************************************************************
290 * ImmGetDefaultIMEWnd (IMM32.@)
291 */
292 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
293 {
294 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
295 return NULL;
296
297 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
298 if (hWnd == NULL)
299 return (HWND)NtUserGetThreadState(3);
300
301 return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME);
302 }
303
304 /***********************************************************************
305 * ImmNotifyIME (IMM32.@)
306 */
307 BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
308 {
309 HKL hKL;
310 PIMEDPI pImeDpi;
311 BOOL ret;
312
313 TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue);
314
315 if (hIMC && Imm32IsCrossThreadAccess(hIMC))
316 return FALSE;
317
318 hKL = GetKeyboardLayout(0);
319 pImeDpi = ImmLockImeDpi(hKL);
320 if (pImeDpi == NULL)
321 return FALSE;
322
323 ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
324 ImmUnlockImeDpi(pImeDpi);
325 return ret;
326 }
327
328 /***********************************************************************
329 * ImmDisableLegacyIME(IMM32.@)
330 */
331 BOOL WINAPI ImmDisableLegacyIME(void)
332 {
333 FIXME("stub\n");
334 return TRUE;
335 }
336
337 /***********************************************************************
338 * CtfImmIsTextFrameServiceDisabled(IMM32.@)
339 */
340 BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID)
341 {
342 PTEB pTeb = NtCurrentTeb();
343 if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->CI_flags & CI_TFSDISABLED)
344 return TRUE;
345 return FALSE;
346 }
347
348 /***********************************************************************
349 * ImmGetImeInfoEx (IMM32.@)
350 */
351 BOOL WINAPI
352 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey)
353 {
354 BOOL bDisabled = FALSE;
355 HKL hKL;
356 PTEB pTeb;
357
358 switch (SearchType)
359 {
360 case ImeInfoExKeyboardLayout:
361 break;
362
363 case ImeInfoExImeWindow:
364 bDisabled = CtfImmIsTextFrameServiceDisabled();
365 SearchType = ImeInfoExKeyboardLayout;
366 break;
367
368 case ImeInfoExImeFileName:
369 StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile),
370 pvSearchKey);
371 goto Quit;
372 }
373
374 hKL = *(HKL*)pvSearchKey;
375 pImeInfoEx->hkl = hKL;
376
377 if (!IS_IME_HKL(hKL))
378 {
379 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
380 {
381 pTeb = NtCurrentTeb();
382 if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->W32ClientInfo[0] & 2)
383 return FALSE;
384 if (!bDisabled)
385 goto Quit;
386 }
387 return FALSE;
388 }
389
390 Quit:
391 return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
392 }
393
394 /***********************************************************************
395 * ImmLockImeDpi (IMM32.@)
396 */
397 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL)
398 {
399 PIMEDPI pImeDpi = NULL;
400
401 TRACE("(%p)\n", hKL);
402
403 RtlEnterCriticalSection(&g_csImeDpi);
404
405 /* Find by hKL */
406 for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
407 {
408 if (pImeDpi->hKL == hKL) /* found */
409 {
410 /* lock if possible */
411 if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN)
412 pImeDpi = NULL;
413 else
414 ++(pImeDpi->cLockObj);
415 break;
416 }
417 }
418
419 RtlLeaveCriticalSection(&g_csImeDpi);
420 return pImeDpi;
421 }
422
423 /***********************************************************************
424 * ImmUnlockImeDpi (IMM32.@)
425 */
426 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi)
427 {
428 PIMEDPI *ppEntry;
429
430 TRACE("(%p)\n", pImeDpi);
431
432 if (pImeDpi == NULL)
433 return;
434
435 RtlEnterCriticalSection(&g_csImeDpi);
436
437 /* unlock */
438 --(pImeDpi->cLockObj);
439 if (pImeDpi->cLockObj != 0)
440 {
441 RtlLeaveCriticalSection(&g_csImeDpi);
442 return;
443 }
444
445 if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0)
446 {
447 if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 ||
448 (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0)
449 {
450 RtlLeaveCriticalSection(&g_csImeDpi);
451 return;
452 }
453 }
454
455 /* Remove from list */
456 for (ppEntry = &g_pImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext))
457 {
458 if (*ppEntry == pImeDpi) /* found */
459 {
460 *ppEntry = pImeDpi->pNext;
461 break;
462 }
463 }
464
465 Imm32FreeImeDpi(pImeDpi, TRUE);
466 HeapFree(g_hImm32Heap, 0, pImeDpi);
467
468 RtlLeaveCriticalSection(&g_csImeDpi);
469 }
470
471 /***********************************************************************
472 * ImmLoadIME (IMM32.@)
473 */
474 BOOL WINAPI ImmLoadIME(HKL hKL)
475 {
476 PW32CLIENTINFO pInfo;
477 PIMEDPI pImeDpi;
478
479 if (!IS_IME_HKL(hKL))
480 {
481 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
482 return FALSE;
483
484 pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo);
485 if ((pInfo->W32ClientInfo[0] & 2))
486 return FALSE;
487 }
488
489 pImeDpi = Imm32FindImeDpi(hKL);
490 if (pImeDpi == NULL)
491 pImeDpi = Ime32LoadImeDpi(hKL, FALSE);
492 return (pImeDpi != NULL);
493 }
494
495 /***********************************************************************
496 * ImmDisableIME (IMM32.@)
497 */
498 BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
499 {
500 return NtUserDisableThreadIme(dwThreadId);
501 }
502
503 /***********************************************************************
504 * ImmGetDescriptionA (IMM32.@)
505 */
506 UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen)
507 {
508 IMEINFOEX info;
509 size_t cch;
510
511 TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
512
513 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
514 return 0;
515
516 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
517 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
518 lpszDescription, uBufLen, NULL, NULL);
519 if (uBufLen)
520 lpszDescription[cch] = 0;
521 return (UINT)cch;
522 }
523
524 /***********************************************************************
525 * ImmGetDescriptionW (IMM32.@)
526 */
527 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
528 {
529 IMEINFOEX info;
530 size_t cch;
531
532 TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
533
534 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
535 return 0;
536
537 if (uBufLen != 0)
538 StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
539
540 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
541 return (UINT)cch;
542 }
543
544 /***********************************************************************
545 * ImmGetIMEFileNameA (IMM32.@)
546 */
547 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
548 {
549 BOOL bDefUsed;
550 IMEINFOEX info;
551 size_t cch;
552
553 TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
554
555 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
556 {
557 if (uBufLen > 0)
558 lpszFileName[0] = 0;
559 return 0;
560 }
561
562 StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
563
564 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch,
565 lpszFileName, uBufLen, NULL, &bDefUsed);
566 if (uBufLen == 0)
567 return (UINT)cch;
568
569 if (cch > uBufLen - 1)
570 cch = uBufLen - 1;
571
572 lpszFileName[cch] = 0;
573 return (UINT)cch;
574 }
575
576 /***********************************************************************
577 * ImmGetIMEFileNameW (IMM32.@)
578 */
579 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
580 {
581 IMEINFOEX info;
582 size_t cch;
583
584 TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
585
586 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
587 {
588 if (uBufLen > 0)
589 lpszFileName[0] = 0;
590 return 0;
591 }
592
593 StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
594 if (uBufLen == 0)
595 return (UINT)cch;
596
597 StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch);
598
599 if (cch > uBufLen - 1)
600 cch = uBufLen - 1;
601
602 lpszFileName[cch] = 0;
603 return (UINT)cch;
604 }
605
606 /***********************************************************************
607 * ImmGetProperty (IMM32.@)
608 */
609 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
610 {
611 IMEINFOEX ImeInfoEx;
612 LPIMEINFO pImeInfo;
613 DWORD dwValue;
614 PIMEDPI pImeDpi = NULL;
615
616 TRACE("(%p, %lu)\n", hKL, fdwIndex);
617
618 if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
619 return FALSE;
620
621 if (fdwIndex == IGP_GETIMEVERSION)
622 return ImeInfoEx.dwImeWinVersion;
623
624 if (ImeInfoEx.fLoadFlag != 2)
625 {
626 pImeDpi = ImmLockOrLoadImeDpi(hKL);
627 if (pImeDpi == NULL)
628 return FALSE;
629
630 pImeInfo = &pImeDpi->ImeInfo;
631 }
632 else
633 {
634 pImeInfo = &ImeInfoEx.ImeInfo;
635 }
636
637 switch (fdwIndex)
638 {
639 case IGP_PROPERTY: dwValue = pImeInfo->fdwProperty; break;
640 case IGP_CONVERSION: dwValue = pImeInfo->fdwConversionCaps; break;
641 case IGP_SENTENCE: dwValue = pImeInfo->fdwSentenceCaps; break;
642 case IGP_UI: dwValue = pImeInfo->fdwUICaps; break;
643 case IGP_SETCOMPSTR: dwValue = pImeInfo->fdwSCSCaps; break;
644 case IGP_SELECT: dwValue = pImeInfo->fdwSelectCaps; break;
645 default: dwValue = 0; break;
646 }
647
648 if (pImeDpi)
649 ImmUnlockImeDpi(pImeDpi);
650 return dwValue;
651 }
652
653 /***********************************************************************
654 * ImmGetOpenStatus (IMM32.@)
655 */
656 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
657 {
658 BOOL ret;
659 LPINPUTCONTEXT pIC;
660
661 TRACE("(%p)\n", hIMC);
662
663 if (!hIMC)
664 return FALSE;
665
666 pIC = ImmLockIMC(hIMC);
667 if (!pIC)
668 return FALSE;
669
670 ret = pIC->fOpen;
671
672 ImmUnlockIMC(hIMC);
673 return ret;
674 }
675
676 /***********************************************************************
677 * ImmSetOpenStatus (IMM32.@)
678 */
679 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
680 {
681 DWORD dwConversion;
682 LPINPUTCONTEXT pIC;
683 HWND hWnd;
684 BOOL bHasChange = FALSE;
685
686 TRACE("(%p, %d)\n", hIMC, fOpen);
687
688 if (Imm32IsCrossThreadAccess(hIMC))
689 return FALSE;
690
691 pIC = ImmLockIMC(hIMC);
692 if (pIC == NULL)
693 return FALSE;
694
695 if (pIC->fOpen != fOpen)
696 {
697 pIC->fOpen = fOpen;
698 hWnd = pIC->hWnd;
699 dwConversion = pIC->fdwConversion;
700 bHasChange = TRUE;
701 }
702
703 ImmUnlockIMC(hIMC);
704
705 if (bHasChange)
706 {
707 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
708 IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0);
709 NtUserNotifyIMEStatus(hWnd, hIMC, dwConversion);
710 }
711
712 return TRUE;
713 }
714
715 /***********************************************************************
716 * ImmGetStatusWindowPos (IMM32.@)
717 */
718 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
719 {
720 LPINPUTCONTEXT pIC;
721 BOOL ret;
722
723 TRACE("(%p, %p)\n", hIMC, lpptPos);
724
725 pIC = ImmLockIMC(hIMC);
726 if (pIC == NULL)
727 return FALSE;
728
729 ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS);
730 if (ret)
731 *lpptPos = pIC->ptStatusWndPos;
732
733 ImmUnlockIMC(hIMC);
734 return ret;
735 }
736
737 /***********************************************************************
738 * ImmSetStatusWindowPos (IMM32.@)
739 */
740 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
741 {
742 LPINPUTCONTEXT pIC;
743 HWND hWnd;
744
745 TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y);
746
747 if (Imm32IsCrossThreadAccess(hIMC))
748 return FALSE;
749
750 pIC = ImmLockIMC(hIMC);
751 if (!pIC)
752 return FALSE;
753
754 hWnd = pIC->hWnd;
755 pIC->ptStatusWndPos = *lpptPos;
756 pIC->fdwInit |= INIT_STATUSWNDPOS;
757
758 ImmUnlockIMC(hIMC);
759
760 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
761 IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0);
762 return TRUE;
763 }
764
765 /***********************************************************************
766 * ImmGetCompositionWindow (IMM32.@)
767 */
768 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
769 {
770 LPINPUTCONTEXT pIC;
771 BOOL ret = FALSE;
772
773 TRACE("(%p, %p)\n", hIMC, lpCompForm);
774
775 pIC = ImmLockIMC(hIMC);
776 if (!pIC)
777 return FALSE;
778
779 if (pIC->fdwInit & INIT_COMPFORM)
780 {
781 *lpCompForm = pIC->cfCompForm;
782 ret = TRUE;
783 }
784
785 ImmUnlockIMC(hIMC);
786 return ret;
787 }
788
789 /***********************************************************************
790 * ImmSetCompositionWindow (IMM32.@)
791 */
792 BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
793 {
794 LPINPUTCONTEXT pIC;
795 HWND hWnd;
796
797 if (Imm32IsCrossThreadAccess(hIMC))
798 return FALSE;
799
800 pIC = ImmLockIMC(hIMC);
801 if (pIC == NULL)
802 return FALSE;
803
804 pIC->cfCompForm = *lpCompForm;
805 pIC->fdwInit |= INIT_COMPFORM;
806
807 hWnd = pIC->hWnd;
808
809 ImmUnlockIMC(hIMC);
810
811 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
812 IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0);
813 return TRUE;
814 }
815
816 /***********************************************************************
817 * ImmGetCompositionFontA (IMM32.@)
818 */
819 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
820 {
821 PCLIENTIMC pClientImc;
822 BOOL ret = FALSE, bWide;
823 LPINPUTCONTEXT pIC;
824
825 TRACE("(%p, %p)\n", hIMC, lplf);
826
827 pClientImc = ImmLockClientImc(hIMC);
828 if (pClientImc == NULL)
829 return FALSE;
830
831 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
832 ImmUnlockClientImc(pClientImc);
833
834 pIC = ImmLockIMC(hIMC);
835 if (pIC == NULL)
836 return FALSE;
837
838 if (pIC->fdwInit & INIT_LOGFONT)
839 {
840 if (bWide)
841 LogFontWideToAnsi(&pIC->lfFont.W, lplf);
842 else
843 *lplf = pIC->lfFont.A;
844
845 ret = TRUE;
846 }
847
848 ImmUnlockIMC(hIMC);
849 return ret;
850 }
851
852 /***********************************************************************
853 * ImmGetCompositionFontW (IMM32.@)
854 */
855 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
856 {
857 PCLIENTIMC pClientImc;
858 BOOL bWide;
859 LPINPUTCONTEXT pIC;
860 BOOL ret = FALSE;
861
862 TRACE("(%p, %p)\n", hIMC, lplf);
863
864 pClientImc = ImmLockClientImc(hIMC);
865 if (pClientImc == NULL)
866 return FALSE;
867
868 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
869 ImmUnlockClientImc(pClientImc);
870
871 pIC = ImmLockIMC(hIMC);
872 if (pIC == NULL)
873 return FALSE;
874
875 if (pIC->fdwInit & INIT_LOGFONT)
876 {
877 if (bWide)
878 *lplf = pIC->lfFont.W;
879 else
880 LogFontAnsiToWide(&pIC->lfFont.A, lplf);
881
882 ret = TRUE;
883 }
884
885 ImmUnlockIMC(hIMC);
886 return ret;
887 }
888
889 /***********************************************************************
890 * ImmSetCompositionFontA (IMM32.@)
891 */
892 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
893 {
894 LOGFONTW lfW;
895 PCLIENTIMC pClientImc;
896 BOOL bWide;
897 LPINPUTCONTEXTDX pIC;
898 LCID lcid;
899 HWND hWnd;
900 PTEB pTeb;
901
902 TRACE("(%p, %p)\n", hIMC, lplf);
903
904 if (Imm32IsCrossThreadAccess(hIMC))
905 return FALSE;
906
907 pClientImc = ImmLockClientImc(hIMC);
908 if (pClientImc == NULL)
909 return FALSE;
910
911 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
912 ImmUnlockClientImc(pClientImc);
913
914 if (bWide)
915 {
916 LogFontAnsiToWide(lplf, &lfW);
917 return ImmSetCompositionFontW(hIMC, &lfW);
918 }
919
920 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
921 if (pIC == NULL)
922 return FALSE;
923
924 pTeb = NtCurrentTeb();
925 if (pTeb->Win32ClientInfo[2] < 0x400)
926 {
927 lcid = GetSystemDefaultLCID();
928 if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) &&
929 pIC->cfCompForm.dwStyle != CFS_DEFAULT)
930 {
931 PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
932 }
933 }
934
935 pIC->lfFont.A = *lplf;
936 pIC->fdwInit |= INIT_LOGFONT;
937 hWnd = pIC->hWnd;
938
939 ImmUnlockIMC(hIMC);
940
941 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
942 IMN_SETCOMPOSITIONFONT, 0);
943 return TRUE;
944 }
945
946 /***********************************************************************
947 * ImmSetCompositionFontW (IMM32.@)
948 */
949 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
950 {
951 LOGFONTA lfA;
952 PCLIENTIMC pClientImc;
953 BOOL bWide;
954 HWND hWnd;
955 LPINPUTCONTEXTDX pIC;
956 PTEB pTeb;
957 LCID lcid;
958
959 TRACE("(%p, %p)\n", hIMC, lplf);
960
961 if (Imm32IsCrossThreadAccess(hIMC))
962 return FALSE;
963
964 pClientImc = ImmLockClientImc(hIMC);
965 if (pClientImc == NULL)
966 return FALSE;
967
968 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
969 ImmUnlockClientImc(pClientImc);
970
971 if (!bWide)
972 {
973 LogFontWideToAnsi(lplf, &lfA);
974 return ImmSetCompositionFontA(hIMC, &lfA);
975 }
976
977 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
978 if (pIC == NULL)
979 return FALSE;
980
981 pTeb = NtCurrentTeb();
982 if (pTeb->Win32ClientInfo[2] < 0x400)
983 {
984 lcid = GetSystemDefaultLCID();
985 if (PRIMARYLANGID(lcid) == LANG_JAPANESE &&
986 !(pIC->dwUIFlags & 2) &&
987 pIC->cfCompForm.dwStyle != CFS_DEFAULT)
988 {
989 PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
990 }
991 }
992
993 pIC->lfFont.W = *lplf;
994 pIC->fdwInit |= INIT_LOGFONT;
995 hWnd = pIC->hWnd;
996
997 ImmUnlockIMC(hIMC);
998
999 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1000 IMN_SETCOMPOSITIONFONT, 0);
1001 return TRUE;
1002 }
1003
1004 /***********************************************************************
1005 * ImmGetConversionListA (IMM32.@)
1006 */
1007 DWORD WINAPI
1008 ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst,
1009 DWORD dwBufLen, UINT uFlag)
1010 {
1011 DWORD ret = 0;
1012 UINT cb;
1013 LPWSTR pszSrcW = NULL;
1014 LPCANDIDATELIST pCL = NULL;
1015 PIMEDPI pImeDpi;
1016
1017 TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc),
1018 lpDst, dwBufLen, uFlag);
1019
1020 pImeDpi = ImmLockOrLoadImeDpi(hKL);
1021 if (pImeDpi == NULL)
1022 return 0;
1023
1024 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
1025 {
1026 ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1027 ImmUnlockImeDpi(pImeDpi);
1028 return ret;
1029 }
1030
1031 if (pSrc)
1032 {
1033 pszSrcW = Imm32WideFromAnsi(pSrc);
1034 if (pszSrcW == NULL)
1035 goto Quit;
1036 }
1037
1038 cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag);
1039 if (cb == 0)
1040 goto Quit;
1041
1042 pCL = Imm32HeapAlloc(0, cb);
1043 if (pCL == NULL)
1044 goto Quit;
1045
1046 cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag);
1047 if (cb == 0)
1048 goto Quit;
1049
1050 ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, CP_ACP);
1051
1052 Quit:
1053 if (pszSrcW)
1054 HeapFree(g_hImm32Heap, 0, pszSrcW);
1055 if (pCL)
1056 HeapFree(g_hImm32Heap, 0, pCL);
1057 ImmUnlockImeDpi(pImeDpi);
1058 return ret;
1059 }
1060
1061 /***********************************************************************
1062 * ImmGetConversionListW (IMM32.@)
1063 */
1064 DWORD WINAPI
1065 ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1066 DWORD dwBufLen, UINT uFlag)
1067 {
1068 DWORD ret = 0;
1069 INT cb;
1070 PIMEDPI pImeDpi;
1071 LPCANDIDATELIST pCL = NULL;
1072 LPSTR pszSrcA = NULL;
1073
1074 TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc),
1075 lpDst, dwBufLen, uFlag);
1076
1077 pImeDpi = ImmLockOrLoadImeDpi(hKL);
1078 if (!pImeDpi)
1079 return 0;
1080
1081 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
1082 {
1083 ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1084 ImmUnlockImeDpi(pImeDpi);
1085 return ret;
1086 }
1087
1088 if (pSrc)
1089 {
1090 pszSrcA = Imm32AnsiFromWide(pSrc);
1091 if (pszSrcA == NULL)
1092 goto Quit;
1093 }
1094
1095 cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag);
1096 if (cb == 0)
1097 goto Quit;
1098
1099 pCL = Imm32HeapAlloc(0, cb);
1100 if (!pCL)
1101 goto Quit;
1102
1103 cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag);
1104 if (!cb)
1105 goto Quit;
1106
1107 ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, CP_ACP);
1108
1109 Quit:
1110 if (pszSrcA)
1111 HeapFree(g_hImm32Heap, 0, pszSrcA);
1112 if (pCL)
1113 HeapFree(g_hImm32Heap, 0, pCL);
1114 ImmUnlockImeDpi(pImeDpi);
1115 return ret;
1116 }
1117
1118 /***********************************************************************
1119 * ImmGetConversionStatus (IMM32.@)
1120 */
1121 BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1122 {
1123 LPINPUTCONTEXT pIC;
1124
1125 TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
1126
1127 pIC = ImmLockIMC(hIMC);
1128 if (!pIC)
1129 return FALSE;
1130
1131 if (lpfdwConversion)
1132 *lpfdwConversion = pIC->fdwConversion;
1133 if (lpfdwSentence)
1134 *lpfdwSentence = pIC->fdwSentence;
1135
1136 ImmUnlockIMC(hIMC);
1137 return TRUE;
1138 }
1139
1140 /***********************************************************************
1141 * ImmSetConversionStatus (IMM32.@)
1142 */
1143 BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1144 {
1145 HKL hKL;
1146 LPINPUTCONTEXT pIC;
1147 DWORD dwOldConversion, dwOldSentence;
1148 BOOL fConversionChange = FALSE, fSentenceChange = FALSE;
1149 HWND hWnd;
1150
1151 TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence);
1152
1153 hKL = GetKeyboardLayout(0);
1154 if (!IS_IME_HKL(hKL))
1155 {
1156 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
1157 {
1158 FIXME("Cicero\n");
1159 return FALSE;
1160 }
1161 }
1162
1163 if (Imm32IsCrossThreadAccess(hIMC))
1164 return FALSE;
1165
1166 pIC = ImmLockIMC(hIMC);
1167 if (pIC == NULL)
1168 return FALSE;
1169
1170 if (pIC->fdwConversion != fdwConversion)
1171 {
1172 dwOldConversion = pIC->fdwConversion;
1173 pIC->fdwConversion = fdwConversion;
1174 fConversionChange = TRUE;
1175 }
1176
1177 if (pIC->fdwSentence != fdwSentence)
1178 {
1179 dwOldSentence = pIC->fdwSentence;
1180 pIC->fdwSentence = fdwSentence;
1181 fSentenceChange = TRUE;
1182 }
1183
1184 hWnd = pIC->hWnd;
1185 ImmUnlockIMC(hIMC);
1186
1187 if (fConversionChange)
1188 {
1189 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion,
1190 IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0);
1191 NtUserNotifyIMEStatus(hWnd, hIMC, fdwConversion);
1192 }
1193
1194 if (fSentenceChange)
1195 {
1196 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence,
1197 IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0);
1198 }
1199
1200 return TRUE;
1201 }
1202
1203 /***********************************************************************
1204 * ImmConfigureIMEA (IMM32.@)
1205 */
1206 BOOL WINAPI ImmConfigureIMEA(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
1207 {
1208 BOOL ret = FALSE;
1209 PIMEDPI pImeDpi;
1210 REGISTERWORDW RegWordW;
1211 LPREGISTERWORDA pRegWordA;
1212
1213 TRACE("(%p, %p, 0x%lX, %p)", hKL, hWnd, dwMode, lpData);
1214
1215 if (!ValidateHwndNoErr(hWnd) || Imm32IsCrossProcessAccess(hWnd))
1216 return FALSE;
1217
1218 pImeDpi = ImmLockOrLoadImeDpi(hKL);
1219 if (!pImeDpi)
1220 return FALSE;
1221
1222 RtlZeroMemory(&RegWordW, sizeof(RegWordW));
1223
1224 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) || !lpData ||
1225 dwMode != IME_CONFIG_REGISTERWORD)
1226 {
1227 goto DoIt;
1228 }
1229
1230 pRegWordA = lpData;
1231
1232 if (pRegWordA->lpReading)
1233 {
1234 RegWordW.lpReading = Imm32WideFromAnsi(pRegWordA->lpReading);
1235 if (!RegWordW.lpReading)
1236 goto Quit;
1237 }
1238
1239 if (pRegWordA->lpWord)
1240 {
1241 RegWordW.lpWord = Imm32WideFromAnsi(pRegWordA->lpWord);
1242 if (!RegWordW.lpWord)
1243 goto Quit;
1244 }
1245
1246 lpData = &RegWordW;
1247
1248 DoIt:
1249 SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
1250 ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
1251 SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
1252
1253 Quit:
1254 if (RegWordW.lpReading)
1255 HeapFree(g_hImm32Heap, 0, RegWordW.lpReading);
1256 if (RegWordW.lpWord)
1257 HeapFree(g_hImm32Heap, 0, RegWordW.lpWord);
1258 ImmUnlockImeDpi(pImeDpi);
1259 return ret;
1260 }
1261
1262 /***********************************************************************
1263 * ImmConfigureIMEW (IMM32.@)
1264 */
1265 BOOL WINAPI ImmConfigureIMEW(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
1266 {
1267 BOOL ret = FALSE;
1268 PIMEDPI pImeDpi;
1269 REGISTERWORDA RegWordA;
1270 LPREGISTERWORDW pRegWordW;
1271
1272 TRACE("(%p, %p, 0x%lX, %p)", hKL, hWnd, dwMode, lpData);
1273
1274 if (!ValidateHwndNoErr(hWnd) || Imm32IsCrossProcessAccess(hWnd))
1275 return FALSE;
1276
1277 pImeDpi = ImmLockOrLoadImeDpi(hKL);
1278 if (!pImeDpi)
1279 return FALSE;
1280
1281 RtlZeroMemory(&RegWordA, sizeof(RegWordA));
1282
1283 if ((pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) || !lpData ||
1284 dwMode != IME_CONFIG_REGISTERWORD)
1285 {
1286 goto DoIt;
1287 }
1288
1289 pRegWordW = lpData;
1290
1291 if (pRegWordW->lpReading)
1292 {
1293 RegWordA.lpReading = Imm32AnsiFromWide(pRegWordW->lpReading);
1294 if (!RegWordA.lpReading)
1295 goto Quit;
1296 }
1297
1298 if (pRegWordW->lpWord)
1299 {
1300 RegWordA.lpWord = Imm32AnsiFromWide(pRegWordW->lpWord);
1301 if (!RegWordA.lpWord)
1302 goto Quit;
1303 }
1304
1305 lpData = &RegWordA;
1306
1307 DoIt:
1308 SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
1309 ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
1310 SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
1311
1312 Quit:
1313 if (RegWordA.lpReading)
1314 HeapFree(g_hImm32Heap, 0, RegWordA.lpReading);
1315 if (RegWordA.lpWord)
1316 HeapFree(g_hImm32Heap, 0, RegWordA.lpWord);
1317 ImmUnlockImeDpi(pImeDpi);
1318 return ret;
1319 }