Reactos
1/*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing Far-Eastern languages input
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-2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
10 */
11
12#include "precomp.h"
13#include <ndk/exfuncs.h>
14
15WINE_DEFAULT_DEBUG_CHANNEL(imm);
16
17HMODULE ghImm32Inst = NULL; /* The IMM32 instance */
18PSERVERINFO gpsi = NULL;
19SHAREDINFO gSharedInfo = { NULL };
20BYTE gfImmInitialized = FALSE; /* Is IMM32 initialized? */
21ULONG_PTR gHighestUserAddress = 0;
22
23static BOOL ImmInitializeGlobals(HMODULE hMod)
24{
25 NTSTATUS status;
26 SYSTEM_BASIC_INFORMATION SysInfo;
27
28 if (hMod)
29 ghImm32Inst = hMod;
30
31 if (gfImmInitialized)
32 return TRUE;
33
34 status = RtlInitializeCriticalSection(&gcsImeDpi);
35 if (NT_ERROR(status))
36 {
37 ERR("\n");
38 return FALSE;
39 }
40
41 status = NtQuerySystemInformation(SystemBasicInformation, &SysInfo, sizeof(SysInfo), NULL);
42 if (NT_ERROR(status))
43 {
44 ERR("\n");
45 return FALSE;
46 }
47 gHighestUserAddress = SysInfo.MaximumUserModeAddress;
48
49 gfImmInitialized = TRUE;
50 return TRUE;
51}
52
53/***********************************************************************
54 * ImmRegisterClient(IMM32.@)
55 * ( Undocumented, called from user32.dll )
56 */
57BOOL WINAPI
58ImmRegisterClient(
59 _Inout_ PSHAREDINFO ptr,
60 _In_ HINSTANCE hMod)
61{
62 gSharedInfo = *ptr;
63 gpsi = gSharedInfo.psi;
64 return ImmInitializeGlobals(hMod);
65}
66
67/***********************************************************************
68 * ImmLoadLayout (IMM32.@)
69 */
70BOOL WINAPI
71ImmLoadLayout(
72 _In_ HKL hKL,
73 _Inout_ PIMEINFOEX pImeInfoEx)
74{
75 DWORD cbData, dwType;
76 HKEY hKey;
77 LSTATUS error;
78 WCHAR szLayout[MAX_PATH];
79 LPCWSTR pszSubKey;
80
81 TRACE("(%p, %p)\n", hKL, pImeInfoEx);
82
83 /* Choose a key */
84 if (IS_IME_HKL(hKL) || !IS_CICERO_MODE() || IS_16BIT_MODE()) /* Non-Cicero? */
85 {
86 StringCchPrintfW(szLayout, _countof(szLayout), L"%s\\%08lX",
87 REGKEY_KEYBOARD_LAYOUTS, HandleToUlong(hKL));
88 pszSubKey = szLayout;
89 }
90 else /* Cicero */
91 {
92 pszSubKey = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\IMM";
93 }
94
95 /* Open the key */
96 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszSubKey, 0, KEY_READ, &hKey);
97 if (IS_ERROR_UNEXPECTEDLY(error))
98 return FALSE;
99
100 /* Load "IME File" value */
101 cbData = sizeof(pImeInfoEx->wszImeFile);
102 error = RegQueryValueExW(hKey, L"IME File", NULL, &dwType,
103 (LPBYTE)pImeInfoEx->wszImeFile, &cbData);
104
105 /* Avoid buffer overrun */
106 pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = UNICODE_NULL;
107
108 RegCloseKey(hKey);
109
110 if (error != ERROR_SUCCESS || dwType != REG_SZ)
111 return FALSE; /* Failed */
112
113 pImeInfoEx->hkl = hKL;
114 pImeInfoEx->fLoadFlag = 0;
115 return Imm32LoadImeVerInfo(pImeInfoEx);
116}
117
118/***********************************************************************
119 * ImmFreeLayout (IMM32.@)
120 *
121 * NOTE: HKL_SWITCH_TO_NON_IME and HKL_RELEASE_IME are special values for hKL.
122 */
123BOOL WINAPI
124ImmFreeLayout(_In_ HKL hKL)
125{
126 WCHAR szKBD[KL_NAMELENGTH];
127 UINT iKL, cKLs;
128 HKL hOldKL, *pList;
129 PIMEDPI pImeDpi;
130 LANGID LangID;
131
132 TRACE("(%p)\n", hKL);
133
134 hOldKL = GetKeyboardLayout(0);
135
136 if (hKL == HKL_SWITCH_TO_NON_IME)
137 {
138 if (!IS_IME_HKL(hOldKL))
139 return TRUE;
140
141 LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
142
143 cKLs = GetKeyboardLayoutList(0, NULL);
144 if (cKLs)
145 {
146 pList = ImmLocalAlloc(0, cKLs * sizeof(HKL));
147 if (IS_NULL_UNEXPECTEDLY(pList))
148 return FALSE;
149
150 cKLs = GetKeyboardLayoutList(cKLs, pList);
151 for (iKL = 0; iKL < cKLs; ++iKL)
152 {
153 if (!IS_IME_HKL(pList[iKL]))
154 {
155 LangID = LOWORD(pList[iKL]);
156 break;
157 }
158 }
159
160 ImmLocalFree(pList);
161 }
162
163 StringCchPrintfW(szKBD, _countof(szKBD), L"%08X", LangID);
164 if (!LoadKeyboardLayoutW(szKBD, KLF_ACTIVATE))
165 {
166 WARN("Default to English US\n");
167 LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | 0x200);
168 }
169 }
170 else if (hKL == HKL_RELEASE_IME)
171 {
172 RtlEnterCriticalSection(&gcsImeDpi);
173Retry:
174 for (pImeDpi = gpImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
175 {
176 if (Imm32ReleaseIME(pImeDpi->hKL))
177 goto Retry;
178 }
179 RtlLeaveCriticalSection(&gcsImeDpi);
180 }
181 else
182 {
183 if (IS_IME_HKL(hKL) && hKL != hOldKL)
184 Imm32ReleaseIME(hKL);
185 }
186
187 return TRUE;
188}
189
190static VOID
191Imm32SelectInputContext(HKL hNewKL, HKL hOldKL, HIMC hIMC)
192{
193 PCLIENTIMC pClientImc;
194 LPINPUTCONTEXTDX pIC;
195 LPGUIDELINE pGL;
196 LPCANDIDATEINFO pCI;
197 LPCOMPOSITIONSTRING pCS;
198 LOGFONTA LogFontA;
199 LOGFONTW LogFontW;
200 BOOL fOldOpen, bIsNewHKLIme = TRUE, bIsOldHKLIme = TRUE, bClientWide, bNewDpiWide;
201 DWORD cbNewPrivate = 0, cbOldPrivate = 0, dwOldConversion, dwOldSentence, dwSize, dwNewSize;
202 PIMEDPI pNewImeDpi = NULL, pOldImeDpi = NULL;
203 HANDLE hPrivate;
204 PIME_STATE pNewState = NULL, pOldState = NULL;
205
206 pClientImc = ImmLockClientImc(hIMC);
207 if (IS_NULL_UNEXPECTEDLY(pClientImc))
208 return;
209
210 pNewImeDpi = ImmLockImeDpi(hNewKL);
211
212 if (hNewKL != hOldKL)
213 pOldImeDpi = ImmLockImeDpi(hOldKL);
214
215 if (pNewImeDpi)
216 {
217 cbNewPrivate = pNewImeDpi->ImeInfo.dwPrivateDataSize;
218 pClientImc->uCodePage = pNewImeDpi->uCodePage;
219 }
220 else
221 {
222 pClientImc->uCodePage = CP_ACP;
223 }
224
225 if (pOldImeDpi)
226 cbOldPrivate = pOldImeDpi->ImeInfo.dwPrivateDataSize;
227
228 cbNewPrivate = max(cbNewPrivate, sizeof(DWORD));
229 cbOldPrivate = max(cbOldPrivate, sizeof(DWORD));
230
231 if (pClientImc->hKL == hOldKL)
232 {
233 if (pOldImeDpi)
234 {
235 if (IS_IME_HKL(hOldKL))
236 pOldImeDpi->ImeSelect(hIMC, FALSE);
237 else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
238 pOldImeDpi->CtfImeSelectEx(hIMC, FALSE, hOldKL);
239 }
240 pClientImc->hKL = NULL;
241 }
242
243 if (CtfImmIsTextFrameServiceDisabled() && IS_CICERO_MODE() && !IS_16BIT_MODE())
244 {
245 bIsNewHKLIme = IS_IME_HKL(hNewKL);
246 bIsOldHKLIme = IS_IME_HKL(hOldKL);
247 }
248
249 pIC = (LPINPUTCONTEXTDX)Imm32InternalLockIMC(hIMC, FALSE);
250 if (!pIC)
251 {
252 if (pNewImeDpi)
253 {
254 if (IS_IME_HKL(hNewKL))
255 pNewImeDpi->ImeSelect(hIMC, TRUE);
256 else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
257 pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL);
258
259 pClientImc->hKL = hNewKL;
260 }
261 }
262 else
263 {
264 dwOldConversion = pIC->fdwConversion;
265 dwOldSentence = pIC->fdwSentence;
266 fOldOpen = pIC->fOpen;
267
268 if (pNewImeDpi)
269 {
270 bClientWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
271 bNewDpiWide = ImeDpi_IsUnicode(pNewImeDpi);
272 if (bClientWide && !bNewDpiWide)
273 {
274 if (pIC->fdwInit & INIT_LOGFONT)
275 {
276 LogFontWideToAnsi(&pIC->lfFont.W, &LogFontA);
277 pIC->lfFont.A = LogFontA;
278 }
279 pClientImc->dwFlags &= ~CLIENTIMC_WIDE;
280 }
281 else if (!bClientWide && bNewDpiWide)
282 {
283 if (pIC->fdwInit & INIT_LOGFONT)
284 {
285 LogFontAnsiToWide(&pIC->lfFont.A, &LogFontW);
286 pIC->lfFont.W = LogFontW;
287 }
288 pClientImc->dwFlags |= CLIENTIMC_WIDE;
289 }
290 }
291
292 if (cbOldPrivate != cbNewPrivate)
293 {
294 hPrivate = ImmReSizeIMCC(pIC->hPrivate, cbNewPrivate);
295 if (!hPrivate)
296 {
297 ImmDestroyIMCC(pIC->hPrivate);
298 hPrivate = ImmCreateIMCC(cbNewPrivate);
299 }
300 pIC->hPrivate = hPrivate;
301 }
302
303#define MAX_IMCC_SIZE 0x1000
304 dwSize = ImmGetIMCCSize(pIC->hMsgBuf);
305 if (ImmGetIMCCLockCount(pIC->hMsgBuf) || dwSize > MAX_IMCC_SIZE)
306 {
307 ImmDestroyIMCC(pIC->hMsgBuf);
308 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
309 pIC->dwNumMsgBuf = 0;
310 }
311
312 dwSize = ImmGetIMCCSize(pIC->hGuideLine);
313 dwNewSize = sizeof(GUIDELINE);
314 if (ImmGetIMCCLockCount(pIC->hGuideLine) ||
315 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
316 {
317 ImmDestroyIMCC(pIC->hGuideLine);
318 pIC->hGuideLine = ImmCreateIMCC(dwNewSize);
319 pGL = ImmLockIMCC(pIC->hGuideLine);
320 if (pGL)
321 {
322 pGL->dwSize = dwNewSize;
323 ImmUnlockIMCC(pIC->hGuideLine);
324 }
325 }
326
327 dwSize = ImmGetIMCCSize(pIC->hCandInfo);
328 dwNewSize = sizeof(CANDIDATEINFO);
329 if (ImmGetIMCCLockCount(pIC->hCandInfo) ||
330 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
331 {
332 ImmDestroyIMCC(pIC->hCandInfo);
333 pIC->hCandInfo = ImmCreateIMCC(dwNewSize);
334 pCI = ImmLockIMCC(pIC->hCandInfo);
335 if (pCI)
336 {
337 pCI->dwSize = dwNewSize;
338 ImmUnlockIMCC(pIC->hCandInfo);
339 }
340 }
341
342 dwSize = ImmGetIMCCSize(pIC->hCompStr);
343 dwNewSize = sizeof(COMPOSITIONSTRING);
344 if (ImmGetIMCCLockCount(pIC->hCompStr) ||
345 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
346 {
347 ImmDestroyIMCC(pIC->hCompStr);
348 pIC->hCompStr = ImmCreateIMCC(dwNewSize);
349 pCS = ImmLockIMCC(pIC->hCompStr);
350 if (pCS)
351 {
352 pCS->dwSize = dwNewSize;
353 ImmUnlockIMCC(pIC->hCompStr);
354 }
355 }
356#undef MAX_IMCC_SIZE
357
358 if (pOldImeDpi && bIsOldHKLIme)
359 {
360 pOldState = Imm32FetchImeState(pIC, hOldKL);
361 if (pOldState)
362 Imm32SaveImeStateSentence(pIC, pOldState, hOldKL);
363 }
364
365 if (pNewImeDpi && bIsNewHKLIme)
366 pNewState = Imm32FetchImeState(pIC, hNewKL);
367
368 if (pOldState != pNewState)
369 {
370 if (pOldState)
371 {
372 pOldState->fOpen = !!pIC->fOpen;
373 pOldState->dwConversion = pIC->fdwConversion;
374 pOldState->dwConversion &= ~IME_CMODE_EUDC;
375 pOldState->dwSentence = pIC->fdwSentence;
376 pOldState->dwInit = pIC->fdwInit;
377 }
378
379 if (pNewState)
380 {
381 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_FORCE_OPEN)
382 {
383 pIC->dwChange &= ~INPUTCONTEXTDX_CHANGE_FORCE_OPEN;
384 pIC->fOpen = TRUE;
385 }
386 else
387 {
388 pIC->fOpen = pNewState->fOpen;
389 }
390
391 pIC->fdwConversion = pNewState->dwConversion;
392 pIC->fdwConversion &= ~IME_CMODE_EUDC;
393 pIC->fdwSentence = pNewState->dwSentence;
394 pIC->fdwInit = pNewState->dwInit;
395 }
396 }
397
398 if (pNewState)
399 Imm32LoadImeStateSentence(pIC, pNewState, hNewKL);
400
401 if (pNewImeDpi)
402 {
403 if (IS_IME_HKL(hNewKL))
404 pNewImeDpi->ImeSelect(hIMC, TRUE);
405 else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
406 pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL);
407
408 pClientImc->hKL = hNewKL;
409 }
410
411 pIC->dwChange = 0;
412 if (pIC->fOpen != fOldOpen)
413 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_OPEN;
414 if (pIC->fdwConversion != dwOldConversion)
415 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_CONVERSION;
416 if (pIC->fdwSentence != dwOldSentence)
417 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_SENTENCE;
418
419 ImmUnlockIMC(hIMC);
420 }
421
422 ImmUnlockImeDpi(pOldImeDpi);
423 ImmUnlockImeDpi(pNewImeDpi);
424 ImmUnlockClientImc(pClientImc);
425}
426
427typedef struct SELECT_LAYOUT
428{
429 HKL hNewKL;
430 HKL hOldKL;
431} SELECT_LAYOUT, *LPSELECT_LAYOUT;
432
433static BOOL CALLBACK Imm32SelectContextProc(HIMC hIMC, LPARAM lParam)
434{
435 LPSELECT_LAYOUT pSelect = (LPSELECT_LAYOUT)lParam;
436 Imm32SelectInputContext(pSelect->hNewKL, pSelect->hOldKL, hIMC);
437 return TRUE;
438}
439
440static BOOL CALLBACK Imm32NotifyIMEProc(HIMC hIMC, LPARAM lParam)
441{
442 ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, (DWORD)lParam, 0);
443 return TRUE;
444}
445
446/***********************************************************************
447 * ImmActivateLayout (IMM32.@)
448 */
449BOOL WINAPI
450ImmActivateLayout(_In_ HKL hKL)
451{
452 PIMEDPI pImeDpi;
453 HKL hOldKL;
454 LPARAM lParam;
455 HWND hwndDefIME = NULL;
456 SELECT_LAYOUT SelectLayout;
457
458 hOldKL = GetKeyboardLayout(0);
459
460 if (hOldKL == hKL && !(GetWin32ClientInfo()->CI_flags & CI_IMMACTIVATE))
461 return TRUE;
462
463 ImmLoadIME(hKL);
464
465 if (hOldKL != hKL)
466 {
467 pImeDpi = ImmLockImeDpi(hOldKL);
468 if (pImeDpi)
469 {
470 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT)
471 lParam = CPS_COMPLETE;
472 else
473 lParam = CPS_CANCEL;
474 ImmUnlockImeDpi(pImeDpi);
475
476 ImmEnumInputContext(0, Imm32NotifyIMEProc, lParam);
477 }
478
479 hwndDefIME = ImmGetDefaultIMEWnd(NULL);
480 if (IsWindow(hwndDefIME))
481 SendMessageW(hwndDefIME, WM_IME_SELECT, FALSE, (LPARAM)hOldKL);
482
483 NtUserSetThreadLayoutHandles(hKL, hOldKL);
484 }
485
486 SelectLayout.hNewKL = hKL;
487 SelectLayout.hOldKL = hOldKL;
488 ImmEnumInputContext(0, Imm32SelectContextProc, (LPARAM)&SelectLayout);
489
490 if (IsWindow(hwndDefIME))
491 SendMessageW(hwndDefIME, WM_IME_SELECT, TRUE, (LPARAM)hKL);
492
493 return TRUE;
494}
495
496/***********************************************************************
497 * ImmAssociateContext (IMM32.@)
498 */
499HIMC WINAPI
500ImmAssociateContext(
501 _In_ HWND hWnd,
502 _In_opt_ HIMC hIMC)
503{
504 PWND pWnd;
505 HWND hwndFocus;
506 DWORD dwValue;
507 HIMC hOldIMC;
508
509 TRACE("(%p, %p)\n", hWnd, hIMC);
510
511 if (!IS_IMM_MODE())
512 {
513 TRACE("\n");
514 return NULL;
515 }
516
517 pWnd = ValidateHwnd(hWnd);
518 if (IS_NULL_UNEXPECTEDLY(pWnd))
519 return NULL;
520
521 if (hIMC && IS_CROSS_THREAD_HIMC(hIMC))
522 return NULL;
523
524 hOldIMC = pWnd->hImc;
525 if (hOldIMC == hIMC)
526 return hIMC;
527
528 dwValue = NtUserAssociateInputContext(hWnd, hIMC, 0);
529 switch (dwValue)
530 {
531 case 0:
532 return hOldIMC;
533
534 case 1:
535 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
536 if (hwndFocus == hWnd)
537 {
538 ImmSetActiveContext(hWnd, hOldIMC, FALSE);
539 ImmSetActiveContext(hWnd, hIMC, TRUE);
540 }
541 return hOldIMC;
542
543 default:
544 return NULL;
545 }
546}
547
548/***********************************************************************
549 * ImmAssociateContextEx (IMM32.@)
550 */
551BOOL WINAPI
552ImmAssociateContextEx(
553 _In_ HWND hWnd,
554 _In_opt_ HIMC hIMC,
555 _In_ DWORD dwFlags)
556{
557 HWND hwndFocus;
558 PWND pFocusWnd;
559 HIMC hOldIMC = NULL;
560 DWORD dwValue;
561
562 TRACE("(%p, %p, 0x%lX)\n", hWnd, hIMC, dwFlags);
563
564 if (!IS_IMM_MODE())
565 {
566 TRACE("\n");
567 return FALSE;
568 }
569
570 if (hIMC && !(dwFlags & IACE_DEFAULT) && IS_CROSS_THREAD_HIMC(hIMC))
571 return FALSE;
572
573 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
574 pFocusWnd = ValidateHwnd(hwndFocus);
575 if (pFocusWnd)
576 hOldIMC = pFocusWnd->hImc;
577
578 dwValue = NtUserAssociateInputContext(hWnd, hIMC, dwFlags);
579 switch (dwValue)
580 {
581 case 0:
582 return TRUE;
583
584 case 1:
585 pFocusWnd = ValidateHwnd(hwndFocus);
586 if (pFocusWnd)
587 {
588 hIMC = pFocusWnd->hImc;
589 if (hIMC != hOldIMC)
590 {
591 ImmSetActiveContext(hwndFocus, hOldIMC, FALSE);
592 ImmSetActiveContext(hwndFocus, hIMC, TRUE);
593 }
594 }
595 return TRUE;
596
597 default:
598 return FALSE;
599 }
600}
601
602/***********************************************************************
603 * ImmCreateContext (IMM32.@)
604 */
605HIMC WINAPI
606ImmCreateContext(VOID)
607{
608 PCLIENTIMC pClientImc;
609 HIMC hIMC;
610
611 TRACE("()\n");
612
613 if (!IS_IMM_MODE())
614 {
615 TRACE("\n");
616 return NULL;
617 }
618
619 pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
620 if (IS_NULL_UNEXPECTEDLY(pClientImc))
621 return NULL;
622
623 hIMC = NtUserCreateInputContext((ULONG_PTR)pClientImc);
624 if (IS_NULL_UNEXPECTEDLY(hIMC))
625 {
626 ImmLocalFree(pClientImc);
627 return NULL;
628 }
629
630 RtlInitializeCriticalSection(&pClientImc->cs);
631
632 pClientImc->dwCompatFlags = (DWORD)NtUserGetThreadState(THREADSTATE_IMECOMPATFLAGS);
633
634 return hIMC;
635}
636
637static VOID
638Imm32DestroyImeModeSaver(LPINPUTCONTEXTDX pIC)
639{
640 PIME_STATE pState, pNext;
641 PIME_SUBSTATE pSubState, pSubNext;
642
643 for (pState = pIC->pState; pState; pState = pNext)
644 {
645 pNext = pState->pNext;
646
647 for (pSubState = pState->pSubState; pSubState; pSubState = pSubNext)
648 {
649 pSubNext = pSubState->pNext;
650 ImmLocalFree(pSubState);
651 }
652
653 ImmLocalFree(pState);
654 }
655
656 pIC->pState = NULL;
657}
658
659static BOOL
660Imm32DestroyInputContext(HIMC hIMC, HKL hKL, BOOL bKeep)
661{
662 PIMEDPI pImeDpi;
663 LPINPUTCONTEXTDX pIC;
664 PCLIENTIMC pClientImc;
665 PIMC pIMC;
666
667 if (hIMC == NULL)
668 return FALSE;
669
670 if (!IS_IMM_MODE())
671 {
672 TRACE("\n");
673 return FALSE;
674 }
675
676 pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
677 if (IS_NULL_UNEXPECTEDLY(pIMC))
678 return FALSE;
679
680 if (pIMC->head.pti != Imm32CurrentPti())
681 {
682 ERR("Thread mismatch\n");
683 return FALSE;
684 }
685
686 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
687 if (pClientImc == NULL)
688 {
689 TRACE("pClientImc == NULL\n");
690 goto Finish;
691 }
692
693 if ((pClientImc->dwFlags & CLIENTIMC_UNKNOWN2) && !bKeep)
694 {
695 ERR("Can't destroy for CLIENTIMC_UNKNOWN2\n");
696 return FALSE;
697 }
698
699 if (pClientImc->dwFlags & CLIENTIMC_DESTROY)
700 return TRUE;
701
702 InterlockedIncrement(&pClientImc->cLockObj);
703
704 if (IS_NULL_UNEXPECTEDLY(pClientImc->hInputContext))
705 goto Quit;
706
707 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
708 if (IS_NULL_UNEXPECTEDLY(pIC))
709 {
710 ImmUnlockClientImc(pClientImc);
711 return FALSE;
712 }
713
714 CtfImmTIMDestroyInputContext(hIMC);
715
716 if (pClientImc->hKL == hKL)
717 {
718 pImeDpi = ImmLockImeDpi(hKL);
719 if (pImeDpi)
720 {
721 if (IS_IME_HKL(hKL))
722 pImeDpi->ImeSelect(hIMC, FALSE);
723 else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
724 pImeDpi->CtfImeSelectEx(hIMC, FALSE, hKL);
725
726 ImmUnlockImeDpi(pImeDpi);
727 }
728
729 pClientImc->hKL = NULL;
730 }
731
732 ImmDestroyIMCC(pIC->hPrivate);
733 ImmDestroyIMCC(pIC->hMsgBuf);
734 ImmDestroyIMCC(pIC->hGuideLine);
735 ImmDestroyIMCC(pIC->hCandInfo);
736 ImmDestroyIMCC(pIC->hCompStr);
737 Imm32DestroyImeModeSaver(pIC);
738 ImmUnlockIMC(hIMC);
739
740Quit:
741 pClientImc->dwFlags |= CLIENTIMC_DESTROY;
742 ImmUnlockClientImc(pClientImc);
743
744Finish:
745 if (bKeep)
746 return TRUE;
747 return NtUserDestroyInputContext(hIMC);
748}
749
750// NOTE: Windows does recursive call ImmLockIMC here but we don't do so.
751static BOOL
752Imm32CreateInputContext(HIMC hIMC, LPINPUTCONTEXT pIC, PCLIENTIMC pClientImc, HKL hKL, BOOL fSelect)
753{
754 DWORD dwIndex, cbPrivate;
755 PIMEDPI pImeDpi = NULL;
756 LPCOMPOSITIONSTRING pCS;
757 LPCANDIDATEINFO pCI;
758 LPGUIDELINE pGL;
759
760 /* Create IC components */
761 pIC->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
762 pIC->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
763 pIC->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
764 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
765 if (IS_NULL_UNEXPECTEDLY(pIC->hCompStr) ||
766 IS_NULL_UNEXPECTEDLY(pIC->hCandInfo) ||
767 IS_NULL_UNEXPECTEDLY(pIC->hGuideLine) ||
768 IS_NULL_UNEXPECTEDLY(pIC->hMsgBuf))
769 {
770 goto Fail;
771 }
772
773 /* Initialize IC components */
774 pCS = ImmLockIMCC(pIC->hCompStr);
775 if (IS_NULL_UNEXPECTEDLY(pCS))
776 goto Fail;
777 pCS->dwSize = sizeof(COMPOSITIONSTRING);
778 ImmUnlockIMCC(pIC->hCompStr);
779
780 pCI = ImmLockIMCC(pIC->hCandInfo);
781 if (IS_NULL_UNEXPECTEDLY(pCI))
782 goto Fail;
783 pCI->dwSize = sizeof(CANDIDATEINFO);
784 ImmUnlockIMCC(pIC->hCandInfo);
785
786 pGL = ImmLockIMCC(pIC->hGuideLine);
787 if (IS_NULL_UNEXPECTEDLY(pGL))
788 goto Fail;
789 pGL->dwSize = sizeof(GUIDELINE);
790 ImmUnlockIMCC(pIC->hGuideLine);
791
792 pIC->dwNumMsgBuf = 0;
793 pIC->fOpen = FALSE;
794 pIC->fdwConversion = pIC->fdwSentence = 0;
795
796 for (dwIndex = 0; dwIndex < MAX_CANDIDATEFORM; ++dwIndex)
797 pIC->cfCandForm[dwIndex].dwIndex = IMM_INVALID_CANDFORM;
798
799 /* Get private data size */
800 pImeDpi = ImmLockImeDpi(hKL);
801 if (!pImeDpi)
802 {
803 cbPrivate = sizeof(DWORD);
804 }
805 else
806 {
807 /* Update CLIENTIMC */
808 pClientImc->uCodePage = pImeDpi->uCodePage;
809 if (ImeDpi_IsUnicode(pImeDpi))
810 pClientImc->dwFlags |= CLIENTIMC_WIDE;
811
812 cbPrivate = pImeDpi->ImeInfo.dwPrivateDataSize;
813 }
814
815 /* Create private data */
816 pIC->hPrivate = ImmCreateIMCC(cbPrivate);
817 if (IS_NULL_UNEXPECTEDLY(pIC->hPrivate))
818 goto Fail;
819
820 CtfImmTIMCreateInputContext(hIMC);
821
822 if (pImeDpi)
823 {
824 /* Select the IME */
825 if (fSelect)
826 {
827 if (IS_IME_HKL(hKL))
828 pImeDpi->ImeSelect(hIMC, TRUE);
829 else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
830 pImeDpi->CtfImeSelectEx(hIMC, TRUE, hKL);
831 }
832
833 /* Set HKL */
834 pClientImc->hKL = hKL;
835
836 ImmUnlockImeDpi(pImeDpi);
837 }
838
839 return TRUE;
840
841Fail:
842 if (pImeDpi)
843 ImmUnlockImeDpi(pImeDpi);
844
845 pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf);
846 pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine);
847 pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo);
848 pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr);
849 return FALSE;
850}
851
852LPINPUTCONTEXT Imm32InternalLockIMC(HIMC hIMC, BOOL fSelect)
853{
854 HANDLE hIC;
855 LPINPUTCONTEXT pIC = NULL;
856 PCLIENTIMC pClientImc;
857 WORD LangID;
858 DWORD dwThreadId;
859 HKL hOldKL, hNewKL;
860 PIMEDPI pImeDpi = NULL;
861
862 pClientImc = ImmLockClientImc(hIMC);
863 if (!pClientImc)
864 return NULL;
865
866 RtlEnterCriticalSection(&pClientImc->cs);
867
868 if (pClientImc->hInputContext)
869 {
870 pIC = LocalLock(pClientImc->hInputContext);
871 if (IS_NULL_UNEXPECTEDLY(pIC))
872 goto Failure;
873
874 CtfImmTIMCreateInputContext(hIMC);
875 goto Success;
876 }
877
878 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
879 if (dwThreadId == GetCurrentThreadId() && IS_CICERO_MODE() && !IS_16BIT_MODE())
880 {
881 hOldKL = GetKeyboardLayout(0);
882 LangID = LOWORD(hOldKL);
883 hNewKL = UlongToHandle(MAKELONG(LangID, LangID));
884
885 pImeDpi = Imm32FindOrLoadImeDpi(hNewKL);
886 if (pImeDpi)
887 {
888 CtfImmTIMActivate(hNewKL);
889 }
890 }
891
892 if (!NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME))
893 {
894 ERR("No default IME window\n");
895 goto Failure;
896 }
897
898 hIC = LocalAlloc(LHND, sizeof(INPUTCONTEXTDX));
899 pIC = LocalLock(hIC);
900 if (IS_NULL_UNEXPECTEDLY(pIC))
901 {
902 LocalFree(hIC);
903 goto Failure;
904 }
905 pClientImc->hInputContext = hIC;
906
907 hNewKL = GetKeyboardLayout(dwThreadId);
908 if (!Imm32CreateInputContext(hIMC, pIC, pClientImc, hNewKL, fSelect))
909 {
910 LocalUnlock(hIC);
911 pClientImc->hInputContext = LocalFree(hIC);
912 goto Failure;
913 }
914
915Success:
916 RtlLeaveCriticalSection(&pClientImc->cs);
917 InterlockedIncrement(&pClientImc->cLockObj);
918 ImmUnlockClientImc(pClientImc);
919 return pIC;
920
921Failure:
922 RtlLeaveCriticalSection(&pClientImc->cs);
923 ImmUnlockClientImc(pClientImc);
924 return NULL;
925}
926
927/***********************************************************************
928 * ImmDestroyContext (IMM32.@)
929 */
930BOOL WINAPI
931ImmDestroyContext(_In_ HIMC hIMC)
932{
933 HKL hKL;
934
935 TRACE("(%p)\n", hIMC);
936
937 if (!IS_IMM_MODE())
938 {
939 TRACE("\n");
940 return FALSE;
941 }
942
943 if (IS_CROSS_THREAD_HIMC(hIMC))
944 return FALSE;
945
946 hKL = GetKeyboardLayout(0);
947 return Imm32DestroyInputContext(hIMC, hKL, FALSE);
948}
949
950/***********************************************************************
951 * ImmLockClientImc (IMM32.@)
952 */
953PCLIENTIMC WINAPI
954ImmLockClientImc(_In_ HIMC hImc)
955{
956 PIMC pIMC;
957 PCLIENTIMC pClientImc;
958
959 TRACE("(%p)\n", hImc);
960
961 if (IS_NULL_UNEXPECTEDLY(hImc))
962 return NULL;
963
964 pIMC = ValidateHandle(hImc, TYPE_INPUTCONTEXT);
965 if (!pIMC || !Imm32CheckImcProcess(pIMC))
966 return NULL;
967
968 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
969 if (pClientImc)
970 {
971 if (pClientImc->dwFlags & CLIENTIMC_DESTROY)
972 return NULL;
973 goto Finish;
974 }
975
976 pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
977 if (IS_NULL_UNEXPECTEDLY(pClientImc))
978 return NULL;
979
980 RtlInitializeCriticalSection(&pClientImc->cs);
981 pClientImc->dwCompatFlags = (DWORD)NtUserGetThreadState(THREADSTATE_IMECOMPATFLAGS);
982
983 if (!NtUserUpdateInputContext(hImc, UIC_CLIENTIMCDATA, (DWORD_PTR)pClientImc))
984 {
985 ERR("\n");
986 ImmLocalFree(pClientImc);
987 return NULL;
988 }
989
990 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
991
992Finish:
993 InterlockedIncrement(&pClientImc->cLockObj);
994 return pClientImc;
995}
996
997/***********************************************************************
998 * ImmUnlockClientImc (IMM32.@)
999 */
1000VOID WINAPI
1001ImmUnlockClientImc(_Inout_ PCLIENTIMC pClientImc)
1002{
1003 LONG cLocks;
1004 HANDLE hInputContext;
1005
1006 TRACE("(%p)\n", pClientImc);
1007
1008 cLocks = InterlockedDecrement(&pClientImc->cLockObj);
1009 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_DESTROY))
1010 return;
1011
1012 hInputContext = pClientImc->hInputContext;
1013 if (hInputContext)
1014 LocalFree(hInputContext);
1015
1016 RtlDeleteCriticalSection(&pClientImc->cs);
1017 ImmLocalFree(pClientImc);
1018}
1019
1020static HIMC
1021ImmGetSaveContext(
1022 _In_opt_ HWND hWnd,
1023 _In_ DWORD dwContextFlags)
1024{
1025 HIMC hIMC;
1026 PCLIENTIMC pClientImc;
1027 PWND pWnd;
1028
1029 if (!IS_IMM_MODE())
1030 {
1031 TRACE("Not IMM mode.\n");
1032 return NULL;
1033 }
1034
1035 if (!hWnd)
1036 {
1037 hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT);
1038 goto Quit;
1039 }
1040
1041 pWnd = ValidateHwnd(hWnd);
1042 if (IS_NULL_UNEXPECTEDLY(pWnd) || IS_CROSS_PROCESS_HWND(hWnd))
1043 return NULL;
1044
1045 hIMC = pWnd->hImc;
1046 if (!hIMC && (dwContextFlags & 1))
1047 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
1048
1049Quit:
1050 pClientImc = ImmLockClientImc(hIMC);
1051 if (IS_NULL_UNEXPECTEDLY(pClientImc))
1052 return NULL;
1053
1054 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_DISABLEIME))
1055 hIMC = NULL;
1056
1057 ImmUnlockClientImc(pClientImc);
1058 return hIMC;
1059}
1060
1061/***********************************************************************
1062 * ImmGetContext (IMM32.@)
1063 */
1064HIMC WINAPI
1065ImmGetContext(_In_ HWND hWnd)
1066{
1067 TRACE("(%p)\n", hWnd);
1068 if (IS_NULL_UNEXPECTEDLY(hWnd))
1069 return NULL;
1070 return ImmGetSaveContext(hWnd, 2);
1071}
1072
1073/***********************************************************************
1074 * ImmLockIMC(IMM32.@)
1075 *
1076 * NOTE: This is not ImmLockIMCC. Don't confuse.
1077 */
1078LPINPUTCONTEXT WINAPI
1079ImmLockIMC(_In_ HIMC hIMC)
1080{
1081 TRACE("(%p)\n", hIMC);
1082 return Imm32InternalLockIMC(hIMC, TRUE);
1083}
1084
1085/***********************************************************************
1086* ImmUnlockIMC(IMM32.@)
1087*/
1088BOOL WINAPI
1089ImmUnlockIMC(_In_ HIMC hIMC)
1090{
1091 PCLIENTIMC pClientImc;
1092
1093 pClientImc = ImmLockClientImc(hIMC);
1094 if (IS_NULL_UNEXPECTEDLY(pClientImc))
1095 return FALSE;
1096
1097 if (pClientImc->hInputContext)
1098 LocalUnlock(pClientImc->hInputContext);
1099
1100 InterlockedDecrement(&pClientImc->cLockObj);
1101 ImmUnlockClientImc(pClientImc);
1102 return TRUE;
1103}
1104
1105/***********************************************************************
1106 * ImmReleaseContext (IMM32.@)
1107 */
1108BOOL WINAPI
1109ImmReleaseContext(
1110 _In_ HWND hWnd,
1111 _In_ HIMC hIMC)
1112{
1113 TRACE("(%p, %p)\n", hWnd, hIMC);
1114 UNREFERENCED_PARAMETER(hWnd);
1115 UNREFERENCED_PARAMETER(hIMC);
1116 return TRUE; // Do nothing. This is correct.
1117}
1118
1119/***********************************************************************
1120 * ImmEnumInputContext(IMM32.@)
1121 */
1122BOOL WINAPI
1123ImmEnumInputContext(
1124 _In_ DWORD dwThreadId,
1125 _In_ IMCENUMPROC lpfn,
1126 _In_ LPARAM lParam)
1127{
1128 HIMC *phList;
1129 DWORD dwIndex, dwCount;
1130 BOOL ret = TRUE;
1131 HIMC hIMC;
1132
1133 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
1134
1135 dwCount = Imm32BuildHimcList(dwThreadId, &phList);
1136 if (IS_ZERO_UNEXPECTEDLY(dwCount))
1137 return FALSE;
1138
1139 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
1140 {
1141 hIMC = phList[dwIndex];
1142 ret = (*lpfn)(hIMC, lParam);
1143 if (!ret)
1144 break;
1145 }
1146
1147 ImmLocalFree(phList);
1148 return ret;
1149}
1150
1151/***********************************************************************
1152 * ImmSetActiveContext(IMM32.@)
1153 */
1154BOOL WINAPI
1155ImmSetActiveContext(
1156 _In_ HWND hWnd,
1157 _In_opt_ HIMC hIMC,
1158 _In_ BOOL fActive)
1159{
1160 PCLIENTIMC pClientImc;
1161 LPINPUTCONTEXTDX pIC;
1162 PIMEDPI pImeDpi;
1163 HIMC hOldIMC;
1164 HKL hKL;
1165 BOOL fOpen = FALSE;
1166 DWORD dwConversion = 0, dwShowFlags = ISC_SHOWUIALL;
1167 HWND hwndDefIME;
1168
1169 TRACE("(%p, %p, %d)\n", hWnd, hIMC, fActive);
1170
1171 if (!IS_IMM_MODE())
1172 {
1173 TRACE("\n");
1174 return FALSE;
1175 }
1176
1177 pClientImc = ImmLockClientImc(hIMC);
1178
1179 if (!fActive)
1180 {
1181 if (pClientImc)
1182 pClientImc->dwFlags &= ~CLIENTIMC_ACTIVE;
1183 }
1184 else if (hIMC)
1185 {
1186 if (IS_NULL_UNEXPECTEDLY(pClientImc))
1187 return FALSE;
1188
1189 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1190 if (IS_NULL_UNEXPECTEDLY(pIC))
1191 {
1192 ImmUnlockClientImc(pClientImc);
1193 return FALSE;
1194 }
1195
1196 pIC->hWnd = hWnd;
1197 pClientImc->dwFlags |= CLIENTIMC_ACTIVE;
1198
1199 if (pIC->dwUIFlags & 2)
1200 dwShowFlags = (ISC_SHOWUIGUIDELINE | ISC_SHOWUIALLCANDIDATEWINDOW);
1201
1202 fOpen = pIC->fOpen;
1203 dwConversion = pIC->fdwConversion;
1204
1205 ImmUnlockIMC(hIMC);
1206 }
1207 else
1208 {
1209 hOldIMC = ImmGetSaveContext(hWnd, 1);
1210 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hOldIMC);
1211 if (pIC)
1212 {
1213 pIC->hWnd = hWnd;
1214 ImmUnlockIMC(hOldIMC);
1215 }
1216 }
1217
1218 hKL = GetKeyboardLayout(0);
1219 if (IS_CICERO_MODE() && !IS_16BIT_MODE())
1220 {
1221 CtfImeSetActiveContextAlways(hIMC, fActive, hWnd, hKL);
1222 hKL = GetKeyboardLayout(0);
1223 }
1224
1225 pImeDpi = ImmLockImeDpi(hKL);
1226 if (pImeDpi)
1227 {
1228 if (IS_IME_HKL(hKL))
1229 pImeDpi->ImeSetActiveContext(hIMC, fActive);
1230 ImmUnlockImeDpi(pImeDpi);
1231 }
1232
1233 if (IsWindow(hWnd))
1234 {
1235 SendMessageW(hWnd, WM_IME_SETCONTEXT, fActive, dwShowFlags);
1236 if (fActive)
1237 NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
1238 }
1239 else if (!fActive)
1240 {
1241 hwndDefIME = ImmGetDefaultIMEWnd(NULL);
1242 if (hwndDefIME)
1243 SendMessageW(hwndDefIME, WM_IME_SETCONTEXT, 0, dwShowFlags);
1244 }
1245
1246 if (pClientImc)
1247 ImmUnlockClientImc(pClientImc);
1248
1249 return TRUE;
1250}
1251
1252/***********************************************************************
1253 * ImmWINNLSGetEnableStatus (IMM32.@)
1254 */
1255BOOL WINAPI
1256ImmWINNLSGetEnableStatus(_In_opt_ HWND hWnd)
1257{
1258 if (!Imm32IsSystemJapaneseOrKorean())
1259 {
1260 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1261 return FALSE;
1262 }
1263
1264 return !!ImmGetSaveContext(hWnd, 2);
1265}
1266
1267/***********************************************************************
1268 * ImmSetActiveContextConsoleIME(IMM32.@)
1269 */
1270BOOL WINAPI
1271ImmSetActiveContextConsoleIME(
1272 _In_ HWND hwnd,
1273 _In_ BOOL fFlag)
1274{
1275 HIMC hIMC;
1276 TRACE("(%p, %d)\n", hwnd, fFlag);
1277
1278 hIMC = ImmGetContext(hwnd);
1279 if (IS_NULL_UNEXPECTEDLY(hIMC))
1280 return FALSE;
1281 return ImmSetActiveContext(hwnd, hIMC, fFlag);
1282}
1283
1284/***********************************************************************
1285 * GetKeyboardLayoutCP (IMM32.@)
1286 */
1287UINT WINAPI GetKeyboardLayoutCP(_In_ LANGID wLangId)
1288{
1289 WCHAR szText[8];
1290 static LANGID s_wKeyboardLangIdCache = 0;
1291 static UINT s_uKeyboardLayoutCPCache = 0;
1292
1293 TRACE("(%u)\n", wLangId);
1294
1295 if (wLangId == s_wKeyboardLangIdCache)
1296 return s_uKeyboardLayoutCPCache;
1297
1298 if (!GetLocaleInfoW(wLangId, LOCALE_IDEFAULTANSICODEPAGE, szText, _countof(szText)))
1299 return 0;
1300
1301 s_wKeyboardLangIdCache = wLangId;
1302 szText[_countof(szText) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1303 s_uKeyboardLayoutCPCache = wcstol(szText, NULL, 10);
1304 return s_uKeyboardLayoutCPCache;
1305}
1306
1307#ifndef NDEBUG
1308VOID Imm32UnitTest(VOID)
1309{
1310 if (0)
1311 {
1312 DWORD dwValue;
1313 WCHAR szText[64];
1314
1315 Imm32StrToUInt(L"123", &dwValue, 10);
1316 ASSERT(dwValue == 123);
1317 Imm32StrToUInt(L"100", &dwValue, 16);
1318 ASSERT(dwValue == 0x100);
1319
1320 Imm32UIntToStr(123, 10, szText, _countof(szText));
1321 ASSERT(lstrcmpW(szText, L"123") == 0);
1322 Imm32UIntToStr(0x100, 16, szText, _countof(szText));
1323 ASSERT(lstrcmpW(szText, L"100") == 0);
1324 }
1325}
1326#endif
1327
1328BOOL
1329WINAPI
1330ImmDllInitialize(
1331 _In_ HINSTANCE hDll,
1332 _In_ ULONG dwReason,
1333 _In_opt_ PVOID pReserved)
1334{
1335 HKL hKL;
1336 HIMC hIMC;
1337
1338 TRACE("(%p, 0x%X, %p)\n", hDll, dwReason, pReserved);
1339
1340 switch (dwReason)
1341 {
1342 case DLL_PROCESS_ATTACH:
1343 if (!ImmInitializeGlobals(hDll))
1344 {
1345 ERR("ImmInitializeGlobals failed\n");
1346 return FALSE;
1347 }
1348 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
1349 {
1350 ERR("User32InitializeImmEntryTable failed\n");
1351 return FALSE;
1352 }
1353#ifndef NDEBUG
1354 Imm32UnitTest();
1355#endif
1356 break;
1357
1358 case DLL_THREAD_ATTACH:
1359 break;
1360
1361 case DLL_THREAD_DETACH:
1362 if (!IS_IMM_MODE() || NtCurrentTeb()->Win32ThreadInfo == NULL)
1363 return TRUE;
1364
1365 hKL = GetKeyboardLayout(0);
1366 hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT);
1367 Imm32DestroyInputContext(hIMC, hKL, TRUE);
1368 break;
1369
1370 case DLL_PROCESS_DETACH:
1371 RtlDeleteCriticalSection(&gcsImeDpi);
1372 TRACE("imm32.dll is unloaded\n");
1373 break;
1374 }
1375
1376 return TRUE;
1377}