1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing the IMM32 Cicero-aware Text Framework (CTF) 5 * COPYRIGHT: Copyright 2022-2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8 #include "precomp.h" 9 #include <msctf.h> /* for ITfLangBarMgr */ 10 #include <objidl.h> /* for IInitializeSpy */ 11 12 WINE_DEFAULT_DEBUG_CHANNEL(imm); 13 14 /* FIXME: Use RTL */ 15 static BOOL WINAPI RtlDllShutdownInProgress(VOID) 16 { 17 return FALSE; 18 } 19 20 static BOOL Imm32InsideLoaderLock(VOID) 21 { 22 return NtCurrentTeb()->ProcessEnvironmentBlock->LoaderLock->OwningThread == 23 NtCurrentTeb()->ClientId.UniqueThread; 24 } 25 26 static BOOL 27 Imm32IsInteractiveUserLogon(VOID) 28 { 29 BOOL bOK, IsMember = FALSE; 30 PSID pSid; 31 SID_IDENTIFIER_AUTHORITY IdentAuth = { SECURITY_NT_AUTHORITY }; 32 33 if (!AllocateAndInitializeSid(&IdentAuth, 1, SECURITY_INTERACTIVE_RID, 34 0, 0, 0, 0, 0, 0, 0, &pSid)) 35 { 36 ERR("Error: %ld\n", GetLastError()); 37 return FALSE; 38 } 39 40 bOK = CheckTokenMembership(NULL, pSid, &IsMember); 41 42 if (pSid) 43 FreeSid(pSid); 44 45 return bOK && IsMember; 46 } 47 48 static BOOL 49 Imm32IsRunningInMsoobe(VOID) 50 { 51 LPWSTR pchFilePart = NULL; 52 WCHAR Buffer[MAX_PATH], FileName[MAX_PATH]; 53 54 if (!GetModuleFileNameW(NULL, FileName, _countof(FileName))) 55 return FALSE; 56 57 GetFullPathNameW(FileName, _countof(Buffer), Buffer, &pchFilePart); 58 if (!pchFilePart) 59 return FALSE; 60 61 return lstrcmpiW(pchFilePart, L"msoobe.exe") == 0; 62 } 63 64 static BOOL 65 Imm32IsCUASEnabledInRegistry(VOID) 66 { 67 HKEY hKey; 68 LSTATUS error; 69 DWORD dwType, dwData, cbData; 70 71 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\CTF\\SystemShared", &hKey); 72 if (error != ERROR_SUCCESS) 73 return FALSE; 74 75 dwData = 0; 76 cbData = sizeof(dwData); 77 error = RegQueryValueExW(hKey, L"CUAS", NULL, &dwType, (LPBYTE)&dwData, &cbData); 78 RegCloseKey(hKey); 79 80 if (error != ERROR_SUCCESS || dwType != REG_DWORD) 81 return FALSE; 82 83 return !!dwData; 84 } 85 86 BOOL 87 Imm32GetFn( 88 _Inout_opt_ FARPROC *ppfn, 89 _Inout_ HINSTANCE *phinstDLL, 90 _In_ LPCWSTR pszDllName, 91 _In_ LPCSTR pszFuncName) 92 { 93 WCHAR szPath[MAX_PATH]; 94 95 if (*ppfn) 96 return TRUE; 97 98 if (*phinstDLL == NULL) 99 { 100 Imm32GetSystemLibraryPath(szPath, _countof(szPath), pszDllName); 101 *phinstDLL = LoadLibraryExW(szPath, NULL, 0); 102 if (*phinstDLL == NULL) 103 return FALSE; 104 } 105 106 *ppfn = (FARPROC)GetProcAddress(*phinstDLL, pszFuncName); 107 return *ppfn != NULL; 108 } 109 110 #define IMM32_GET_FN(ppfn, phinstDLL, dll_name, func_name) \ 111 Imm32GetFn((FARPROC*)(ppfn), (phinstDLL), (dll_name), #func_name) 112 113 /*********************************************************************** 114 * OLE32.DLL 115 */ 116 117 HINSTANCE g_hOle32 = NULL; 118 119 #define OLE32_FN(name) g_pfnOLE32_##name 120 121 typedef HRESULT (WINAPI *FN_CoInitializeEx)(LPVOID, DWORD); 122 typedef VOID (WINAPI *FN_CoUninitialize)(VOID); 123 typedef HRESULT (WINAPI *FN_CoRegisterInitializeSpy)(IInitializeSpy*, ULARGE_INTEGER*); 124 typedef HRESULT (WINAPI *FN_CoRevokeInitializeSpy)(ULARGE_INTEGER); 125 126 FN_CoInitializeEx OLE32_FN(CoInitializeEx) = NULL; 127 FN_CoUninitialize OLE32_FN(CoUninitialize) = NULL; 128 FN_CoRegisterInitializeSpy OLE32_FN(CoRegisterInitializeSpy) = NULL; 129 FN_CoRevokeInitializeSpy OLE32_FN(CoRevokeInitializeSpy) = NULL; 130 131 #define Imm32GetOle32Fn(func_name) \ 132 IMM32_GET_FN(&OLE32_FN(func_name), &g_hOle32, L"ole32.dll", #func_name) 133 134 HRESULT Imm32CoInitializeEx(VOID) 135 { 136 if (!Imm32GetOle32Fn(CoInitializeEx)) 137 return E_FAIL; 138 139 return OLE32_FN(CoInitializeEx)(NULL, COINIT_APARTMENTTHREADED); 140 } 141 142 VOID Imm32CoUninitialize(VOID) 143 { 144 if (!Imm32GetOle32Fn(CoUninitialize)) 145 return; 146 147 OLE32_FN(CoUninitialize)(); 148 } 149 150 HRESULT Imm32CoRegisterInitializeSpy(IInitializeSpy* spy, ULARGE_INTEGER* cookie) 151 { 152 if (!Imm32GetOle32Fn(CoRegisterInitializeSpy)) 153 return E_FAIL; 154 155 return OLE32_FN(CoRegisterInitializeSpy)(spy, cookie); 156 } 157 158 HRESULT Imm32CoRevokeInitializeSpy(ULARGE_INTEGER cookie) 159 { 160 if (!Imm32GetOle32Fn(CoRevokeInitializeSpy)) 161 return E_FAIL; 162 163 return OLE32_FN(CoRevokeInitializeSpy)(cookie); 164 } 165 166 /*********************************************************************** 167 * MSCTF.DLL 168 */ 169 170 HINSTANCE g_hMsctf = NULL; 171 172 #define MSCTF_FN(name) g_pfnMSCTF_##name 173 174 typedef HRESULT (WINAPI *FN_TF_CreateLangBarMgr)(ITfLangBarMgr**); 175 typedef VOID (WINAPI *FN_TF_InvalidAssemblyListCacheIfExist)(VOID); 176 177 FN_TF_CreateLangBarMgr MSCTF_FN(TF_CreateLangBarMgr) = NULL; 178 FN_TF_InvalidAssemblyListCacheIfExist MSCTF_FN(TF_InvalidAssemblyListCacheIfExist) = NULL; 179 180 #define Imm32GetMsctfFn(func_name) \ 181 IMM32_GET_FN(&MSCTF_FN(func_name), &g_hMsctf, L"msctf.dll", #func_name) 182 183 HRESULT Imm32TF_CreateLangBarMgr(_Inout_ ITfLangBarMgr **ppBarMgr) 184 { 185 TRACE("TF_CreateLangBarMgr(%p)\n", ppBarMgr); 186 187 if (!Imm32GetMsctfFn(TF_CreateLangBarMgr)) 188 return E_FAIL; 189 190 return MSCTF_FN(TF_CreateLangBarMgr)(ppBarMgr); 191 } 192 193 VOID Imm32TF_InvalidAssemblyListCacheIfExist(VOID) 194 { 195 TRACE("TF_InvalidAssemblyListCacheIfExist()\n"); 196 197 if (!Imm32GetMsctfFn(TF_InvalidAssemblyListCacheIfExist)) 198 return; 199 200 MSCTF_FN(TF_InvalidAssemblyListCacheIfExist)(); 201 } 202 203 /*********************************************************************** 204 * CTF IME support 205 * 206 * TSF stands for "Text Services Framework". "Cicero" is the code name of TSF. 207 * CTF stands for "Cicero-aware Text Framework". 208 * 209 * Comparing with old-style IMM IME, the combination of CTF IME and TSF provides 210 * new-style and high-level input method. 211 * 212 * The CTF IME file is a DLL file that the software developer distributes. 213 * The export functions of the CTF IME file are defined in <CtfImeTable.h> of 214 * this folder. 215 */ 216 217 /* "Active IMM" compatibility flags */ 218 DWORD g_aimm_compat_flags = 0; 219 220 /* Disable CUAS? */ 221 BOOL g_disable_CUAS_flag = FALSE; 222 223 /* The instance of the CTF IME file */ 224 HINSTANCE g_hCtfIme = NULL; 225 226 /* Define the function types (FN_...) for CTF IME functions */ 227 #undef DEFINE_CTF_IME_FN 228 #define DEFINE_CTF_IME_FN(func_name, ret_type, params) \ 229 typedef ret_type (WINAPI *FN_##func_name)params; 230 #include <CtfImeTable.h> 231 232 /* Define the global variables (g_pfn...) for CTF IME functions */ 233 #undef DEFINE_CTF_IME_FN 234 #define DEFINE_CTF_IME_FN(func_name, ret_type, params) \ 235 FN_##func_name g_pfn##func_name = NULL; 236 #include <CtfImeTable.h> 237 238 /* The macro that gets the variable name from the CTF IME function name */ 239 #define CTF_IME_FN(func_name) g_pfn##func_name 240 241 /* The type of ApphelpCheckIME function in apphelp.dll */ 242 typedef BOOL (WINAPI *FN_ApphelpCheckIME)(_In_z_ LPCWSTR AppName); 243 244 /* FIXME: This is kernel32 function. We have to declare this in some header. */ 245 BOOL WINAPI 246 BaseCheckAppcompatCache(_In_z_ LPCWSTR ApplicationName, 247 _In_ HANDLE FileHandle, 248 _In_opt_z_ LPCWSTR Environment, 249 _Out_ PULONG pdwReason); 250 251 /*********************************************************************** 252 * This function checks whether the app's IME is disabled by application 253 * compatibility patcher. 254 */ 255 BOOL 256 Imm32CheckAndApplyAppCompat( 257 _In_ ULONG dwReason, 258 _In_z_ LPCWSTR pszAppName) 259 { 260 HINSTANCE hinstApphelp; 261 FN_ApphelpCheckIME pApphelpCheckIME; 262 263 /* Query the application compatibility patcher */ 264 if (BaseCheckAppcompatCache(pszAppName, INVALID_HANDLE_VALUE, NULL, &dwReason)) 265 return TRUE; /* The app's IME is not disabled */ 266 267 /* Load apphelp.dll if necessary */ 268 hinstApphelp = GetModuleHandleW(L"apphelp.dll"); 269 if (!hinstApphelp) 270 { 271 hinstApphelp = LoadLibraryW(L"apphelp.dll"); 272 if (!hinstApphelp) 273 return TRUE; /* There is no apphelp.dll. The app's IME is not disabled */ 274 } 275 276 /* Is ApphelpCheckIME implemented? */ 277 pApphelpCheckIME = (FN_ApphelpCheckIME)GetProcAddress(hinstApphelp, "ApphelpCheckIME"); 278 if (!pApphelpCheckIME) 279 return TRUE; /* Not implemented. The app's IME is not disabled */ 280 281 /* Is the app's IME disabled or not? */ 282 return pApphelpCheckIME(pszAppName); 283 } 284 285 /*********************************************************************** 286 * TLS (Thread-Local Storage) 287 * 288 * See: TlsAlloc 289 */ 290 291 DWORD g_dwTLSIndex = -1; 292 293 /* IMM Thread-Local Storage (TLS) data */ 294 typedef struct IMMTLSDATA 295 { 296 IInitializeSpy *pSpy; /* CoInitialize Spy */ 297 DWORD dwUnknown1; 298 ULARGE_INTEGER uliCookie; /* Spy requires a cookie for revoking */ 299 BOOL bDoCount; /* Is it counting? */ 300 DWORD dwSkipCount; /* The skipped count */ 301 BOOL bUninitializing; /* Is it uninitializing? */ 302 DWORD dwUnknown2; 303 } IMMTLSDATA, *PIMMTLSDATA; 304 305 static VOID 306 Imm32InitTLS(VOID) 307 { 308 RtlEnterCriticalSection(&gcsImeDpi); 309 310 if (g_dwTLSIndex == -1) 311 g_dwTLSIndex = TlsAlloc(); 312 313 RtlLeaveCriticalSection(&gcsImeDpi); 314 } 315 316 static IMMTLSDATA* 317 Imm32AllocateTLS(VOID) 318 { 319 IMMTLSDATA *pData; 320 321 if (g_dwTLSIndex == -1) 322 return NULL; 323 324 pData = (IMMTLSDATA*)TlsGetValue(g_dwTLSIndex); 325 if (pData) 326 return pData; 327 328 pData = (IMMTLSDATA*)ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IMMTLSDATA)); 329 if (IS_NULL_UNEXPECTEDLY(pData)) 330 return NULL; 331 332 if (IS_FALSE_UNEXPECTEDLY(TlsSetValue(g_dwTLSIndex, pData))) 333 { 334 ImmLocalFree(pData); 335 return NULL; 336 } 337 338 return pData; 339 } 340 341 static IMMTLSDATA* 342 Imm32GetTLS(VOID) 343 { 344 if (g_dwTLSIndex == -1) 345 return NULL; 346 347 return (IMMTLSDATA*)TlsGetValue(g_dwTLSIndex); 348 } 349 350 /* Get */ 351 static DWORD 352 Imm32GetCoInitCountSkip(VOID) 353 { 354 IMMTLSDATA *pData = Imm32GetTLS(); 355 if (!pData) 356 return 0; 357 return pData->dwSkipCount; 358 } 359 360 /* Increment */ 361 static DWORD 362 Imm32IncCoInitCountSkip(VOID) 363 { 364 IMMTLSDATA *pData; 365 DWORD dwOldSkipCount; 366 367 pData = Imm32GetTLS(); 368 if (!pData) 369 return 0; 370 371 dwOldSkipCount = pData->dwSkipCount; 372 if (pData->bDoCount) 373 pData->dwSkipCount = dwOldSkipCount + 1; 374 375 return dwOldSkipCount; 376 } 377 378 /* Decrement */ 379 static DWORD 380 Imm32DecCoInitCountSkip(VOID) 381 { 382 DWORD dwSkipCount; 383 IMMTLSDATA *pData; 384 385 pData = Imm32GetTLS();; 386 if (!pData) 387 return 0; 388 389 dwSkipCount = pData->dwSkipCount; 390 if (pData->bDoCount) 391 { 392 if (dwSkipCount) 393 pData->dwSkipCount = dwSkipCount - 1; 394 } 395 396 return dwSkipCount; 397 } 398 399 /*********************************************************************** 400 * CtfImmEnterCoInitCountSkipMode (IMM32.@) 401 */ 402 VOID WINAPI CtfImmEnterCoInitCountSkipMode(VOID) 403 { 404 IMMTLSDATA *pData; 405 406 TRACE("()\n"); 407 408 pData = Imm32GetTLS(); 409 if (pData) 410 ++(pData->bDoCount); 411 } 412 413 /*********************************************************************** 414 * CtfImmLeaveCoInitCountSkipMode (IMM32.@) 415 */ 416 BOOL WINAPI CtfImmLeaveCoInitCountSkipMode(VOID) 417 { 418 IMMTLSDATA *pData; 419 420 TRACE("()\n"); 421 422 pData = Imm32GetTLS(); 423 if (!pData || !pData->bDoCount) 424 return FALSE; 425 426 --(pData->bDoCount); 427 return TRUE; 428 } 429 430 /*********************************************************************** 431 * ISPY (I am not spy!) 432 * 433 * ISPY watches CoInitialize[Ex] / CoUninitialize to manage COM initialization status. 434 */ 435 436 typedef struct ISPY 437 { 438 const IInitializeSpyVtbl *m_pSpyVtbl; 439 LONG m_cRefs; 440 } ISPY, *PISPY; 441 442 static STDMETHODIMP 443 ISPY_QueryInterface( 444 _Inout_ IInitializeSpy *pThis, 445 _In_ REFIID riid, 446 _Inout_ LPVOID *ppvObj) 447 { 448 ISPY *pSpy = (ISPY*)pThis; 449 450 if (!ppvObj) 451 return E_INVALIDARG; 452 453 *ppvObj = NULL; 454 455 if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid, &IID_IInitializeSpy)) 456 return E_NOINTERFACE; 457 458 ++(pSpy->m_cRefs); 459 *ppvObj = pSpy; 460 return S_OK; 461 } 462 463 static STDMETHODIMP_(ULONG) 464 ISPY_AddRef( 465 _Inout_ IInitializeSpy *pThis) 466 { 467 ISPY *pSpy = (ISPY*)pThis; 468 return ++pSpy->m_cRefs; 469 } 470 471 static STDMETHODIMP_(ULONG) 472 ISPY_Release( 473 _Inout_ IInitializeSpy *pThis) 474 { 475 ISPY *pSpy = (ISPY*)pThis; 476 if (--pSpy->m_cRefs == 0) 477 { 478 ImmLocalFree(pSpy); 479 return 0; 480 } 481 return pSpy->m_cRefs; 482 } 483 484 /* 485 * (Pre/Post)(Initialize/Uninitialize) will be automatically called from OLE32 486 * as the results of watching. 487 */ 488 489 static STDMETHODIMP 490 ISPY_PreInitialize( 491 _Inout_ IInitializeSpy *pThis, 492 _In_ DWORD dwCoInit, 493 _In_ DWORD dwCurThreadAptRefs) 494 { 495 DWORD cCount; 496 497 UNREFERENCED_PARAMETER(pThis); 498 499 cCount = Imm32IncCoInitCountSkip(); 500 if (!dwCoInit && 501 (dwCurThreadAptRefs == cCount + 1) && 502 (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT)) 503 { 504 Imm32ActivateOrDeactivateTIM(FALSE); 505 CtfImmCoUninitialize(); 506 } 507 508 return S_OK; 509 } 510 511 static STDMETHODIMP 512 ISPY_PostInitialize( 513 _Inout_ IInitializeSpy *pThis, 514 _In_ HRESULT hrCoInit, 515 _In_ DWORD dwCoInit, 516 _In_ DWORD dwNewThreadAptRefs) 517 { 518 DWORD CoInitCountSkip; 519 520 UNREFERENCED_PARAMETER(pThis); 521 UNREFERENCED_PARAMETER(dwCoInit); 522 523 CoInitCountSkip = Imm32GetCoInitCountSkip(); 524 525 if ((hrCoInit != S_FALSE) || 526 (dwNewThreadAptRefs != CoInitCountSkip + 2) || 527 !(GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT)) 528 { 529 return hrCoInit; 530 } 531 532 return S_OK; 533 } 534 535 static STDMETHODIMP 536 ISPY_PreUninitialize( 537 _Inout_ IInitializeSpy *pThis, 538 _In_ DWORD dwCurThreadAptRefs) 539 { 540 UNREFERENCED_PARAMETER(pThis); 541 542 if (dwCurThreadAptRefs == 1 && 543 !RtlDllShutdownInProgress() && 544 !Imm32InsideLoaderLock() && 545 (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT)) 546 { 547 IMMTLSDATA *pData = Imm32GetTLS(); 548 if (pData && !pData->bUninitializing) 549 Imm32CoInitializeEx(); 550 } 551 552 return S_OK; 553 } 554 555 static STDMETHODIMP 556 ISPY_PostUninitialize( 557 _In_ IInitializeSpy *pThis, 558 _In_ DWORD dwNewThreadAptRefs) 559 { 560 UNREFERENCED_PARAMETER(pThis); 561 UNREFERENCED_PARAMETER(dwNewThreadAptRefs); 562 Imm32DecCoInitCountSkip(); 563 return S_OK; 564 } 565 566 static const IInitializeSpyVtbl g_vtblISPY = 567 { 568 ISPY_QueryInterface, 569 ISPY_AddRef, 570 ISPY_Release, 571 ISPY_PreInitialize, 572 ISPY_PostInitialize, 573 ISPY_PreUninitialize, 574 ISPY_PostUninitialize, 575 }; 576 577 static ISPY* 578 Imm32AllocIMMISPY(VOID) 579 { 580 ISPY *pSpy = (ISPY*)ImmLocalAlloc(0, sizeof(ISPY)); 581 if (!pSpy) 582 return NULL; 583 584 pSpy->m_pSpyVtbl = &g_vtblISPY; 585 pSpy->m_cRefs = 1; 586 return pSpy; 587 } 588 589 #define Imm32DeleteIMMISPY(pSpy) ImmLocalFree(pSpy) 590 591 /*********************************************************************** 592 * CtfImmCoInitialize (Not exported) 593 */ 594 HRESULT 595 CtfImmCoInitialize(VOID) 596 { 597 HRESULT hr; 598 IMMTLSDATA *pData; 599 ISPY *pSpy; 600 601 if (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT) 602 return S_OK; /* Already initialized */ 603 604 hr = Imm32CoInitializeEx(); 605 if (FAILED_UNEXPECTEDLY(hr)) 606 return hr; /* CoInitializeEx failed */ 607 608 GetWin32ClientInfo()->CI_flags |= CI_CTFCOINIT; 609 Imm32InitTLS(); 610 611 pData = Imm32AllocateTLS(); 612 if (!pData || pData->pSpy) 613 return S_OK; /* Cannot allocate or already it has a spy */ 614 615 pSpy = Imm32AllocIMMISPY(); 616 pData->pSpy = (IInitializeSpy*)pSpy; 617 if (IS_NULL_UNEXPECTEDLY(pSpy)) 618 return S_OK; /* Cannot allocate a spy */ 619 620 if (FAILED_UNEXPECTEDLY(Imm32CoRegisterInitializeSpy(pData->pSpy, &pData->uliCookie))) 621 { 622 /* Failed to register the spy */ 623 Imm32DeleteIMMISPY(pData->pSpy); 624 pData->pSpy = NULL; 625 pData->uliCookie.QuadPart = 0; 626 } 627 628 return S_OK; 629 } 630 631 /*********************************************************************** 632 * CtfImmCoUninitialize (IMM32.@) 633 */ 634 VOID WINAPI 635 CtfImmCoUninitialize(VOID) 636 { 637 IMMTLSDATA *pData; 638 639 if (!(GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT)) 640 return; /* Not CoInitialize'd */ 641 642 pData = Imm32GetTLS(); 643 if (pData) 644 { 645 pData->bUninitializing = TRUE; 646 Imm32CoUninitialize(); /* Do CoUninitialize */ 647 pData->bUninitializing = FALSE; 648 649 GetWin32ClientInfo()->CI_flags &= ~CI_CTFCOINIT; 650 } 651 652 pData = Imm32AllocateTLS(); 653 if (!pData || !pData->pSpy) 654 return; /* There were no spy */ 655 656 /* Our work is done. We don't need spies like you anymore. */ 657 Imm32CoRevokeInitializeSpy(pData->uliCookie); 658 ISPY_Release(pData->pSpy); 659 pData->pSpy = NULL; 660 pData->uliCookie.QuadPart = 0; 661 } 662 663 /*********************************************************************** 664 * This function loads the CTF IME file if necessary and establishes 665 * communication with the CTF IME. 666 */ 667 HINSTANCE 668 Imm32LoadCtfIme(VOID) 669 { 670 BOOL bSuccess = FALSE; 671 IMEINFOEX ImeInfoEx; 672 WCHAR szImeFile[MAX_PATH]; 673 674 /* Lock the IME interface */ 675 RtlEnterCriticalSection(&gcsImeDpi); 676 677 do 678 { 679 if (g_hCtfIme) /* Already loaded? */ 680 { 681 bSuccess = TRUE; 682 break; 683 } 684 685 /* 686 * NOTE: (HKL)0x04090409 is English US keyboard (default). 687 * The Cicero keyboard logically uses English US keyboard. 688 */ 689 if (!ImmLoadLayout((HKL)ULongToHandle(0x04090409), &ImeInfoEx)) 690 break; 691 692 /* Build a path string in system32. The installed IME file must be in system32. */ 693 Imm32GetSystemLibraryPath(szImeFile, _countof(szImeFile), ImeInfoEx.wszImeFile); 694 695 /* Is the CTF IME disabled by app compatibility patcher? */ 696 if (!Imm32CheckAndApplyAppCompat(0, szImeFile)) 697 break; /* This IME is disabled */ 698 699 /* Load a CTF IME file */ 700 g_hCtfIme = LoadLibraryW(szImeFile); 701 if (!g_hCtfIme) 702 break; 703 704 /* Assume success */ 705 bSuccess = TRUE; 706 707 /* Retrieve the CTF IME functions */ 708 #undef DEFINE_CTF_IME_FN 709 #define DEFINE_CTF_IME_FN(func_name, ret_type, params) \ 710 CTF_IME_FN(func_name) = (FN_##func_name)GetProcAddress(g_hCtfIme, #func_name); \ 711 if (!CTF_IME_FN(func_name)) \ 712 { \ 713 bSuccess = FALSE; /* Failed */ \ 714 break; \ 715 } 716 #include <CtfImeTable.h> 717 } while (0); 718 719 /* Unload the CTF IME if failed */ 720 if (!bSuccess) 721 { 722 /* Set NULL to the function pointers */ 723 #undef DEFINE_CTF_IME_FN 724 #define DEFINE_CTF_IME_FN(func_name, ret_type, params) CTF_IME_FN(func_name) = NULL; 725 #include <CtfImeTable.h> 726 727 if (g_hCtfIme) 728 { 729 FreeLibrary(g_hCtfIme); 730 g_hCtfIme = NULL; 731 } 732 } 733 734 /* Unlock the IME interface */ 735 RtlLeaveCriticalSection(&gcsImeDpi); 736 737 return g_hCtfIme; 738 } 739 740 /*********************************************************************** 741 * This function calls the same name function of the CTF IME side. 742 */ 743 HRESULT 744 CtfImeCreateThreadMgr(VOID) 745 { 746 TRACE("()\n"); 747 748 if (!Imm32LoadCtfIme()) 749 return E_FAIL; 750 751 return CTF_IME_FN(CtfImeCreateThreadMgr)(); 752 } 753 754 /*********************************************************************** 755 * This function calls the same name function of the CTF IME side. 756 */ 757 HRESULT 758 CtfImeDestroyThreadMgr(VOID) 759 { 760 TRACE("()\n"); 761 762 if (!Imm32LoadCtfIme()) 763 return E_FAIL; 764 765 return CTF_IME_FN(CtfImeDestroyThreadMgr)(); 766 } 767 768 /*********************************************************************** 769 * CtfAImmIsIME (IMM32.@) 770 * 771 * @return TRUE if CTF IME or IMM IME is enabled. 772 */ 773 BOOL WINAPI 774 CtfAImmIsIME(_In_ HKL hKL) 775 { 776 TRACE("(%p)\n", hKL); 777 if (!Imm32LoadCtfIme()) 778 return ImmIsIME(hKL); 779 return CTF_IME_FN(CtfImeIsIME)(hKL); 780 } 781 782 /*********************************************************************** 783 * CtfImmIsCiceroStartedInThread (IMM32.@) 784 * 785 * @return TRUE if Cicero is started in the current thread. 786 */ 787 BOOL WINAPI 788 CtfImmIsCiceroStartedInThread(VOID) 789 { 790 TRACE("()\n"); 791 return !!(GetWin32ClientInfo()->CI_flags & 0x200); 792 } 793 794 /*********************************************************************** 795 * CtfImmSetCiceroStartInThread (IMM32.@) 796 */ 797 VOID WINAPI CtfImmSetCiceroStartInThread(_In_ BOOL bStarted) 798 { 799 TRACE("(%d)\n", bStarted); 800 if (bStarted) 801 GetWin32ClientInfo()->CI_flags |= 0x200; 802 else 803 GetWin32ClientInfo()->CI_flags &= ~0x200; 804 } 805 806 /*********************************************************************** 807 * CtfImmSetAppCompatFlags (IMM32.@) 808 * 809 * Sets the application compatibility flags. 810 */ 811 VOID WINAPI 812 CtfImmSetAppCompatFlags(_In_ DWORD dwFlags) 813 { 814 TRACE("(0x%08X)\n", dwFlags); 815 if (!(dwFlags & 0xF0FFFFFF)) 816 g_aimm_compat_flags = dwFlags; 817 } 818 819 /*********************************************************************** 820 * This function calls the same name function of the CTF IME side. 821 */ 822 HRESULT 823 CtfImeCreateInputContext( 824 _In_ HIMC hIMC) 825 { 826 TRACE("(%p)\n", hIMC); 827 828 if (!Imm32LoadCtfIme()) 829 return E_FAIL; 830 831 return CTF_IME_FN(CtfImeCreateInputContext)(hIMC); 832 } 833 834 /*********************************************************************** 835 * This function calls the same name function of the CTF IME side. 836 */ 837 HRESULT 838 CtfImeDestroyInputContext(_In_ HIMC hIMC) 839 { 840 TRACE("(%p)\n", hIMC); 841 842 if (!Imm32LoadCtfIme()) 843 return E_FAIL; 844 845 return CTF_IME_FN(CtfImeDestroyInputContext)(hIMC); 846 } 847 848 /*********************************************************************** 849 * The callback function to activate CTF IMEs. Used in CtfAImmActivate. 850 */ 851 static BOOL CALLBACK 852 Imm32EnumCreateCtfICProc( 853 _In_ HIMC hIMC, 854 _In_ LPARAM lParam) 855 { 856 UNREFERENCED_PARAMETER(lParam); 857 CtfImeCreateInputContext(hIMC); 858 return TRUE; /* Continue */ 859 } 860 861 /*********************************************************************** 862 * Thread Input Manager (TIM) 863 */ 864 865 static BOOL 866 Imm32IsTIMDisabledInRegistry(VOID) 867 { 868 DWORD dwData, cbData; 869 HKEY hKey; 870 LSTATUS error; 871 872 error = RegOpenKeyW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF", &hKey); 873 if (error != ERROR_SUCCESS) 874 return FALSE; 875 876 dwData = 0; 877 cbData = sizeof(dwData); 878 RegQueryValueExW(hKey, L"Disable Thread Input Manager", NULL, NULL, (LPBYTE)&dwData, &cbData); 879 RegCloseKey(hKey); 880 return !!dwData; 881 } 882 883 HRESULT 884 Imm32ActivateOrDeactivateTIM( 885 _In_ BOOL bCreate) 886 { 887 HRESULT hr = S_OK; 888 889 if (!IS_CICERO_MODE() || IS_16BIT_MODE() || 890 !(GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT)) 891 { 892 return S_OK; /* No need to activate/de-activate TIM */ 893 } 894 895 if (bCreate) 896 { 897 if (!(GetWin32ClientInfo()->CI_flags & CI_CTFTIM)) 898 { 899 hr = CtfImeCreateThreadMgr(); 900 if (SUCCEEDED(hr)) 901 GetWin32ClientInfo()->CI_flags |= CI_CTFTIM; 902 } 903 } 904 else /* Destroy */ 905 { 906 if (GetWin32ClientInfo()->CI_flags & CI_CTFTIM) 907 { 908 hr = CtfImeDestroyThreadMgr(); 909 if (SUCCEEDED(hr)) 910 GetWin32ClientInfo()->CI_flags &= ~CI_CTFTIM; 911 } 912 } 913 914 return hr; 915 } 916 917 HRESULT 918 CtfImmTIMDestroyInputContext( 919 _In_ HIMC hIMC) 920 { 921 if (!IS_CICERO_MODE() || (GetWin32ClientInfo()->dwCompatFlags2 & 2)) 922 return E_NOINTERFACE; 923 924 return CtfImeDestroyInputContext(hIMC); 925 } 926 927 HRESULT 928 CtfImmTIMCreateInputContext( 929 _In_ HIMC hIMC) 930 { 931 PCLIENTIMC pClientImc; 932 DWORD_PTR dwImeThreadId, dwCurrentThreadId; 933 HRESULT hr = S_FALSE; 934 935 TRACE("(%p)\n", hIMC); 936 937 pClientImc = ImmLockClientImc(hIMC); 938 if (!pClientImc) 939 return E_FAIL; 940 941 if (GetWin32ClientInfo()->CI_flags & CI_AIMMACTIVATED) 942 { 943 if (!pClientImc->bCtfIme) 944 { 945 dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 946 dwCurrentThreadId = GetCurrentThreadId(); 947 if (dwImeThreadId == dwCurrentThreadId) 948 { 949 pClientImc->bCtfIme = TRUE; 950 hr = CtfImeCreateInputContext(hIMC); 951 if (FAILED_UNEXPECTEDLY(hr)) 952 pClientImc->bCtfIme = FALSE; 953 } 954 } 955 } 956 else 957 { 958 if (!(GetWin32ClientInfo()->CI_flags & CI_CTFTIM)) 959 return S_OK; 960 961 if (!pClientImc->bCtfIme) 962 { 963 dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 964 dwCurrentThreadId = GetCurrentThreadId(); 965 if ((dwImeThreadId == dwCurrentThreadId) && IS_CICERO_MODE() && !IS_16BIT_MODE()) 966 { 967 pClientImc->bCtfIme = TRUE; 968 hr = CtfImeCreateInputContext(hIMC); 969 if (FAILED_UNEXPECTEDLY(hr)) 970 pClientImc->bCtfIme = FALSE; 971 } 972 } 973 } 974 975 ImmUnlockClientImc(pClientImc); 976 return hr; 977 } 978 979 /*********************************************************************** 980 * CtfImmLastEnabledWndDestroy (IMM32.@) 981 * 982 * Same as Imm32ActivateOrDeactivateTIM but its naming is improper. 983 */ 984 HRESULT WINAPI 985 CtfImmLastEnabledWndDestroy( 986 _In_ BOOL bCreate) 987 { 988 TRACE("(%d)\n", bCreate); 989 return Imm32ActivateOrDeactivateTIM(bCreate); 990 } 991 992 /*********************************************************************** 993 * CtfAImmActivate (IMM32.@) 994 * 995 * This function activates "Active IMM" (AIMM) and TSF. 996 */ 997 HRESULT WINAPI 998 CtfAImmActivate( 999 _Out_opt_ HINSTANCE *phinstCtfIme) 1000 { 1001 HRESULT hr; 1002 HINSTANCE hinstCtfIme; 1003 1004 TRACE("(%p)\n", phinstCtfIme); 1005 1006 /* Load a CTF IME file if necessary */ 1007 hinstCtfIme = Imm32LoadCtfIme(); 1008 1009 /* Create a thread manager of the CTF IME */ 1010 hr = CtfImeCreateThreadMgr(); 1011 if (hr == S_OK) 1012 { 1013 /* Update CI_... flags of the thread client info */ 1014 GetWin32ClientInfo()->CI_flags |= CI_AIMMACTIVATED; /* Activate AIMM */ 1015 GetWin32ClientInfo()->CI_flags &= ~CI_TSFDISABLED; /* Enable TSF */ 1016 1017 /* Create the CTF input contexts */ 1018 ImmEnumInputContext(0, Imm32EnumCreateCtfICProc, 0); 1019 } 1020 1021 if (phinstCtfIme) 1022 *phinstCtfIme = hinstCtfIme; 1023 1024 return hr; 1025 } 1026 1027 /*********************************************************************** 1028 * CtfAImmDeactivate (IMM32.@) 1029 * 1030 * This function de-activates "Active IMM" (AIMM) and TSF. 1031 */ 1032 HRESULT WINAPI 1033 CtfAImmDeactivate( 1034 _In_ BOOL bDestroy) 1035 { 1036 HRESULT hr; 1037 1038 if (!bDestroy) 1039 return E_FAIL; 1040 1041 hr = CtfImeDestroyThreadMgr(); 1042 if (hr == S_OK) 1043 { 1044 GetWin32ClientInfo()->CI_flags &= ~CI_AIMMACTIVATED; /* Deactivate AIMM */ 1045 GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED; /* Disable TSF */ 1046 } 1047 1048 return hr; 1049 } 1050 1051 /*********************************************************************** 1052 * CtfImmIsCiceroEnabled (IMM32.@) 1053 * 1054 * @return TRUE if Cicero is enabled. 1055 */ 1056 BOOL WINAPI 1057 CtfImmIsCiceroEnabled(VOID) 1058 { 1059 return IS_CICERO_MODE(); 1060 } 1061 1062 /*********************************************************************** 1063 * CtfImmIsTextFrameServiceDisabled (IMM32.@) 1064 * 1065 * @return TRUE if TSF is disabled. 1066 */ 1067 BOOL WINAPI 1068 CtfImmIsTextFrameServiceDisabled(VOID) 1069 { 1070 return !!(GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED); 1071 } 1072 1073 /*********************************************************************** 1074 * ImmDisableTextFrameService (IMM32.@) 1075 */ 1076 BOOL WINAPI 1077 ImmDisableTextFrameService(_In_ DWORD dwThreadId) 1078 { 1079 HRESULT hr = S_OK; 1080 1081 TRACE("(0x%lX)\n", dwThreadId); 1082 1083 if (dwThreadId == -1) 1084 g_disable_CUAS_flag = TRUE; 1085 1086 if ((dwThreadId && !g_disable_CUAS_flag) || (GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED)) 1087 return TRUE; 1088 1089 GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED; 1090 1091 if (IS_CICERO_MODE() && !IS_16BIT_MODE() && 1092 (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT) && 1093 (GetWin32ClientInfo()->CI_flags & CI_CTFTIM)) 1094 { 1095 hr = CtfImeDestroyThreadMgr(); 1096 if (SUCCEEDED(hr)) 1097 { 1098 GetWin32ClientInfo()->CI_flags &= ~CI_CTFTIM; 1099 CtfImmCoUninitialize(); 1100 } 1101 } 1102 1103 return hr == S_OK; 1104 } 1105 1106 /*********************************************************************** 1107 * CtfImmTIMActivate (IMM32.@) 1108 * 1109 * Activates Thread Input Manager (TIM) in the thread. 1110 */ 1111 HRESULT WINAPI 1112 CtfImmTIMActivate(_In_ HKL hKL) 1113 { 1114 HRESULT hr = S_OK; 1115 1116 TRACE("(%p)\n", hKL); 1117 1118 if (g_disable_CUAS_flag) 1119 { 1120 TRACE("g_disable_CUAS_flag\n"); 1121 GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED; 1122 return FALSE; 1123 } 1124 1125 if (GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED) 1126 { 1127 TRACE("CI_TSFDISABLED\n"); 1128 return FALSE; 1129 } 1130 1131 if (Imm32IsTIMDisabledInRegistry()) 1132 { 1133 TRACE("TIM is disabled in registry\n"); 1134 GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED; 1135 return FALSE; 1136 } 1137 1138 if (!Imm32IsInteractiveUserLogon() || Imm32IsRunningInMsoobe()) 1139 { 1140 TRACE("TIM is disabled due to LOGON or MSOBE\n"); 1141 return FALSE; 1142 } 1143 1144 if (!Imm32IsCUASEnabledInRegistry()) 1145 { 1146 TRACE("CUAS is disabled in registry\n"); 1147 GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED; 1148 return FALSE; 1149 } 1150 1151 if (NtCurrentTeb()->ProcessEnvironmentBlock->AppCompatFlags.LowPart & 0x100) 1152 { 1153 TRACE("CUAS is disabled by AppCompatFlags\n"); 1154 GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED; 1155 return FALSE; 1156 } 1157 1158 if (RtlIsThreadWithinLoaderCallout() || Imm32InsideLoaderLock()) 1159 { 1160 TRACE("TIM is disabled by Loader\n"); 1161 return FALSE; 1162 } 1163 1164 if (!IS_CICERO_MODE() || IS_16BIT_MODE()) 1165 { 1166 TRACE("TIM is disabled because CICERO mode is unset\n"); 1167 return FALSE; 1168 } 1169 1170 if (IS_IME_HKL(hKL)) 1171 hKL = (HKL)UlongToHandle(MAKELONG(LOWORD(hKL), LOWORD(hKL))); 1172 1173 if (!ImmLoadIME(hKL)) 1174 Imm32TF_InvalidAssemblyListCacheIfExist(); 1175 1176 CtfImmCoInitialize(); 1177 1178 if ((GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT) && 1179 !(GetWin32ClientInfo()->CI_flags & CI_CTFTIM)) 1180 { 1181 hr = CtfImeCreateThreadMgr(); 1182 if (SUCCEEDED(hr)) 1183 GetWin32ClientInfo()->CI_flags |= CI_CTFTIM; 1184 } 1185 1186 return hr; 1187 } 1188 1189 /*********************************************************************** 1190 * CtfImmGenerateMessage (IMM32.@) 1191 */ 1192 BOOL WINAPI 1193 CtfImmGenerateMessage( 1194 _In_ HIMC hIMC, 1195 _In_ BOOL bSend) 1196 { 1197 DWORD_PTR dwImeThreadId, dwCurrentThreadId; 1198 PCLIENTIMC pClientImc; 1199 BOOL bUnicode; 1200 LPINPUTCONTEXT pIC; 1201 DWORD iMsg, dwNumMsgBuf; 1202 LPTRANSMSG pOldTransMsg, pNewTransMsg; 1203 SIZE_T cbTransMsg; 1204 1205 TRACE("(%p, %d)\n", hIMC, bSend); 1206 1207 dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 1208 dwCurrentThreadId = GetCurrentThreadId(); 1209 if (dwImeThreadId != dwCurrentThreadId) 1210 { 1211 ERR("%p vs %p\n", dwImeThreadId, dwCurrentThreadId); 1212 return FALSE; 1213 } 1214 1215 pClientImc = ImmLockClientImc(hIMC); 1216 if (IS_NULL_UNEXPECTEDLY(pClientImc)) 1217 return FALSE; 1218 1219 bUnicode = !!(pClientImc->dwFlags & CLIENTIMC_WIDE); 1220 ImmUnlockClientImc(pClientImc); 1221 1222 pIC = (LPINPUTCONTEXT)ImmLockIMC(hIMC); 1223 if (IS_NULL_UNEXPECTEDLY(pIC)) 1224 return FALSE; 1225 1226 dwNumMsgBuf = pIC->dwNumMsgBuf; 1227 pOldTransMsg = (LPTRANSMSG)ImmLockIMCC(pIC->hMsgBuf); 1228 if (IS_NULL_UNEXPECTEDLY(pOldTransMsg)) 1229 { 1230 pIC->dwNumMsgBuf = 0; 1231 ImmUnlockIMC(hIMC); 1232 return TRUE; 1233 } 1234 1235 cbTransMsg = sizeof(TRANSMSG) * dwNumMsgBuf; 1236 pNewTransMsg = (PTRANSMSG)ImmLocalAlloc(0, cbTransMsg); 1237 if (IS_NULL_UNEXPECTEDLY(pNewTransMsg)) 1238 { 1239 ImmUnlockIMCC(pIC->hMsgBuf); 1240 pIC->dwNumMsgBuf = 0; 1241 ImmUnlockIMC(hIMC); 1242 return TRUE; 1243 } 1244 1245 RtlCopyMemory(pNewTransMsg, pOldTransMsg, cbTransMsg); 1246 1247 for (iMsg = 0; iMsg < dwNumMsgBuf; ++iMsg) 1248 { 1249 HWND hWnd = pIC->hWnd; 1250 UINT uMsg = pNewTransMsg[iMsg].message; 1251 WPARAM wParam = pNewTransMsg[iMsg].wParam; 1252 LPARAM lParam = pNewTransMsg[iMsg].lParam; 1253 if (bSend) 1254 { 1255 if (bUnicode) 1256 SendMessageW(hWnd, uMsg, wParam, lParam); 1257 else 1258 SendMessageA(hWnd, uMsg, wParam, lParam); 1259 } 1260 else 1261 { 1262 if (bUnicode) 1263 PostMessageW(hWnd, uMsg, wParam, lParam); 1264 else 1265 PostMessageA(hWnd, uMsg, wParam, lParam); 1266 } 1267 } 1268 1269 ImmLocalFree(pNewTransMsg); 1270 ImmUnlockIMCC(pIC->hMsgBuf); 1271 pIC->dwNumMsgBuf = 0; /* Processed */ 1272 ImmUnlockIMC(hIMC); 1273 1274 return TRUE; 1275 } 1276 1277 /*********************************************************************** 1278 * CtfImmHideToolbarWnd (IMM32.@) 1279 * 1280 * Used with CtfImmRestoreToolbarWnd. 1281 */ 1282 DWORD WINAPI 1283 CtfImmHideToolbarWnd(VOID) 1284 { 1285 ITfLangBarMgr *pBarMgr; 1286 DWORD dwShowFlags = 0; 1287 BOOL bShown; 1288 1289 TRACE("()\n"); 1290 1291 if (FAILED(Imm32TF_CreateLangBarMgr(&pBarMgr))) 1292 return dwShowFlags; 1293 1294 if (SUCCEEDED(pBarMgr->lpVtbl->GetShowFloatingStatus(pBarMgr, &dwShowFlags))) 1295 { 1296 bShown = !(dwShowFlags & 0x800); 1297 dwShowFlags &= 0xF; 1298 if (bShown) 1299 pBarMgr->lpVtbl->ShowFloating(pBarMgr, 8); 1300 } 1301 1302 pBarMgr->lpVtbl->Release(pBarMgr); 1303 return dwShowFlags; 1304 } 1305 1306 /*********************************************************************** 1307 * CtfImmRestoreToolbarWnd (IMM32.@) 1308 * 1309 * Used with CtfImmHideToolbarWnd. 1310 */ 1311 VOID WINAPI 1312 CtfImmRestoreToolbarWnd( 1313 _In_ LPVOID pUnused, 1314 _In_ DWORD dwShowFlags) 1315 { 1316 HRESULT hr; 1317 ITfLangBarMgr *pBarMgr; 1318 1319 UNREFERENCED_PARAMETER(pUnused); 1320 1321 TRACE("(%p, 0x%X)\n", pUnused, dwShowFlags); 1322 1323 hr = Imm32TF_CreateLangBarMgr(&pBarMgr); 1324 if (FAILED_UNEXPECTEDLY(hr)) 1325 return; 1326 1327 if (dwShowFlags) 1328 pBarMgr->lpVtbl->ShowFloating(pBarMgr, dwShowFlags); 1329 1330 pBarMgr->lpVtbl->Release(pBarMgr); 1331 } 1332 1333 /*********************************************************************** 1334 * CtfImmDispatchDefImeMessage (IMM32.@) 1335 */ 1336 LRESULT WINAPI 1337 CtfImmDispatchDefImeMessage( 1338 _In_ HWND hWnd, 1339 _In_ UINT uMsg, 1340 _In_ WPARAM wParam, 1341 _In_ LPARAM lParam) 1342 { 1343 TRACE("(%p, %u, %p, %p)\n", hWnd, uMsg, wParam, lParam); 1344 1345 if (RtlDllShutdownInProgress() || Imm32InsideLoaderLock() || !Imm32LoadCtfIme()) 1346 return 0; 1347 1348 return CTF_IME_FN(CtfImeDispatchDefImeMessage)(hWnd, uMsg, wParam, lParam); 1349 } 1350 1351 /*********************************************************************** 1352 * CtfImmIsGuidMapEnable (IMM32.@) 1353 */ 1354 BOOL WINAPI 1355 CtfImmIsGuidMapEnable( 1356 _In_ HIMC hIMC) 1357 { 1358 DWORD dwThreadId; 1359 HKL hKL; 1360 PIMEDPI pImeDpi; 1361 BOOL ret = FALSE; 1362 1363 TRACE("(%p)\n", hIMC); 1364 1365 if (!IS_CICERO_MODE() || IS_16BIT_MODE()) 1366 return ret; 1367 1368 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 1369 hKL = GetKeyboardLayout(dwThreadId); 1370 1371 if (IS_IME_HKL(hKL)) 1372 return ret; 1373 1374 pImeDpi = Imm32FindOrLoadImeDpi(hKL); 1375 if (IS_NULL_UNEXPECTEDLY(pImeDpi)) 1376 return ret; 1377 1378 ret = pImeDpi->CtfImeIsGuidMapEnable(hIMC); 1379 1380 ImmUnlockImeDpi(pImeDpi); 1381 return ret; 1382 } 1383 1384 /*********************************************************************** 1385 * CtfImmGetGuidAtom (IMM32.@) 1386 */ 1387 HRESULT WINAPI 1388 CtfImmGetGuidAtom( 1389 _In_ HIMC hIMC, 1390 _In_ DWORD dwUnknown, 1391 _Out_ LPDWORD pdwGuidAtom) 1392 { 1393 HRESULT hr = E_FAIL; 1394 PIMEDPI pImeDpi; 1395 DWORD dwThreadId; 1396 HKL hKL; 1397 1398 TRACE("(%p, 0xlX, %p)\n", hIMC, dwUnknown, pdwGuidAtom); 1399 1400 *pdwGuidAtom = 0; 1401 1402 if (!IS_CICERO_MODE() || IS_16BIT_MODE()) 1403 return hr; 1404 1405 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 1406 hKL = GetKeyboardLayout(dwThreadId); 1407 if (IS_IME_HKL(hKL)) 1408 return S_OK; 1409 1410 pImeDpi = Imm32FindOrLoadImeDpi(hKL); 1411 if (IS_NULL_UNEXPECTEDLY(pImeDpi)) 1412 return hr; 1413 1414 hr = pImeDpi->CtfImeGetGuidAtom(hIMC, dwUnknown, pdwGuidAtom); 1415 1416 ImmUnlockImeDpi(pImeDpi); 1417 return hr; 1418 } 1419