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