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