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