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