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