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