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