xref: /reactos/dll/win32/imm32/ctf.c (revision 931224fb)
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