https://git.reactos.org/?p=reactos.git;a=commitdiff;h=931224fbe12c682bfb5c7…
commit 931224fbe12c682bfb5c736528836c9793be453b
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Thu Nov 30 17:22:50 2023 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Thu Nov 30 17:22:50 2023 +0900
[IMM32][SDK][NTUSER] Implement CtfImmTIMActivate (#6041)
- Add Imm32InitTLS, Imm32AllocateTLS, Imm32GetTLS,
Imm32GetCoInitCountSkip, Imm32IncCoInitCountSkip, and
Imm32DecCoInitCountSkip helper functions to
control the TLS data.
- Introduce "CoInitialize Spy" (ISPY) to manage COM
initialization status.
- Implement CtfImmCoInitialize and CtfImmCoUninitialize.
- Implement CtfImmEnterCoInitCountSkipMode and
CtfImmLeaveCoInitCountSkipMode.
- Implement CtfImmLastEnabledWndDestroy,
ImmDisableTextFrameService, and CtfImmTIMActivate.
CORE-19268
---
dll/win32/imm32/CMakeLists.txt | 2 +-
dll/win32/imm32/ctf.c | 695 ++++++++++++++++++++++++++++++++++++--
dll/win32/imm32/imm.c | 9 -
dll/win32/imm32/imm32.spec | 4 +
dll/win32/imm32/precomp.h | 9 +
sdk/include/ddk/immdev.h | 4 +-
sdk/include/reactos/imm32_undoc.h | 4 +
win32ss/include/ntuser.h | 2 +
8 files changed, 683 insertions(+), 46 deletions(-)
diff --git a/dll/win32/imm32/CMakeLists.txt b/dll/win32/imm32/CMakeLists.txt
index b765ec172ab..60b146b10fa 100644
--- a/dll/win32/imm32/CMakeLists.txt
+++ b/dll/win32/imm32/CMakeLists.txt
@@ -45,6 +45,6 @@ list(APPEND imm32_rc_deps
add_library(imm32 MODULE ${SOURCE} imm32.rc)
set_module_type(imm32 win32dll UNICODE ENTRYPOINT ImmDllInitialize 12)
set_source_files_properties(imm32.rc PROPERTIES OBJECT_DEPENDS
"${imm32_rc_deps}")
-target_link_libraries(imm32 wine win32ksys)
+target_link_libraries(imm32 wine win32ksys uuid)
add_importlibs(imm32 advapi32 user32 gdi32 kernel32 ntdll)
add_cd_file(TARGET imm32 DESTINATION reactos/system32 FOR all)
diff --git a/dll/win32/imm32/ctf.c b/dll/win32/imm32/ctf.c
index dd325d472f7..be1853f02c3 100644
--- a/dll/win32/imm32/ctf.c
+++ b/dll/win32/imm32/ctf.c
@@ -6,11 +6,83 @@
*/
#include "precomp.h"
-#include <msctf.h>
-#include <ctfutb.h>
+#include <msctf.h> /* for ITfLangBarMgr */
+#include <objidl.h> /* for IInitializeSpy */
WINE_DEFAULT_DEBUG_CHANNEL(imm);
+/* FIXME: Use RTL */
+static BOOL WINAPI RtlDllShutdownInProgress(VOID)
+{
+ return FALSE;
+}
+
+static BOOL Imm32InsideLoaderLock(VOID)
+{
+ return NtCurrentTeb()->ProcessEnvironmentBlock->LoaderLock->OwningThread ==
+ NtCurrentTeb()->ClientId.UniqueThread;
+}
+
+static BOOL
+Imm32IsInteractiveUserLogon(VOID)
+{
+ BOOL bOK, IsMember = FALSE;
+ PSID pSid;
+ SID_IDENTIFIER_AUTHORITY IdentAuth = { SECURITY_NT_AUTHORITY };
+
+ if (!AllocateAndInitializeSid(&IdentAuth, 1, SECURITY_INTERACTIVE_RID,
+ 0, 0, 0, 0, 0, 0, 0, &pSid))
+ {
+ ERR("Error: %ld\n", GetLastError());
+ return FALSE;
+ }
+
+ bOK = CheckTokenMembership(NULL, pSid, &IsMember);
+
+ if (pSid)
+ FreeSid(pSid);
+
+ return bOK && IsMember;
+}
+
+static BOOL
+Imm32IsRunningInMsoobe(VOID)
+{
+ LPWSTR pchFilePart = NULL;
+ WCHAR Buffer[MAX_PATH], FileName[MAX_PATH];
+
+ if (!GetModuleFileNameW(NULL, FileName, _countof(FileName)))
+ return FALSE;
+
+ GetFullPathNameW(FileName, _countof(Buffer), Buffer, &pchFilePart);
+ if (!pchFilePart)
+ return FALSE;
+
+ return lstrcmpiW(pchFilePart, L"msoobe.exe") == 0;
+}
+
+static BOOL
+Imm32IsCUASEnabledInRegistry(VOID)
+{
+ HKEY hKey;
+ LSTATUS error;
+ DWORD dwType, dwData, cbData;
+
+ error = RegOpenKeyW(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\CTF\\SystemShared", &hKey);
+ if (error != ERROR_SUCCESS)
+ return FALSE;
+
+ dwData = 0;
+ cbData = sizeof(dwData);
+ error = RegQueryValueExW(hKey, L"CUAS", NULL, &dwType,
(LPBYTE)&dwData, &cbData);
+ RegCloseKey(hKey);
+
+ if (error != ERROR_SUCCESS || dwType != REG_DWORD)
+ return FALSE;
+
+ return !!dwData;
+}
+
BOOL
Imm32GetFn(
_Inout_opt_ FARPROC *ppfn,
@@ -110,6 +182,8 @@ FN_TF_InvalidAssemblyListCacheIfExist
MSCTF_FN(TF_InvalidAssemblyListCacheIfExis
HRESULT Imm32TF_CreateLangBarMgr(_Inout_ ITfLangBarMgr **ppBarMgr)
{
+ TRACE("TF_CreateLangBarMgr(%p)\n", ppBarMgr);
+
if (!Imm32GetMsctfFn(TF_CreateLangBarMgr))
return E_FAIL;
@@ -118,6 +192,8 @@ HRESULT Imm32TF_CreateLangBarMgr(_Inout_ ITfLangBarMgr **ppBarMgr)
VOID Imm32TF_InvalidAssemblyListCacheIfExist(VOID)
{
+ TRACE("TF_InvalidAssemblyListCacheIfExist()\n");
+
if (!Imm32GetMsctfFn(TF_InvalidAssemblyListCacheIfExist))
return;
@@ -141,6 +217,9 @@ VOID Imm32TF_InvalidAssemblyListCacheIfExist(VOID)
/* "Active IMM" compatibility flags */
DWORD g_aimm_compat_flags = 0;
+/* Disable CUAS? */
+BOOL g_disable_CUAS_flag = FALSE;
+
/* The instance of the CTF IME file */
HINSTANCE g_hCtfIme = NULL;
@@ -203,6 +282,384 @@ Imm32CheckAndApplyAppCompat(
return pApphelpCheckIME(pszAppName);
}
+/***********************************************************************
+ * TLS (Thread-Local Storage)
+ *
+ * See: TlsAlloc
+ */
+
+DWORD g_dwTLSIndex = -1;
+
+/* IMM Thread-Local Storage (TLS) data */
+typedef struct IMMTLSDATA
+{
+ IInitializeSpy *pSpy; /* CoInitialize Spy */
+ DWORD dwUnknown1;
+ ULARGE_INTEGER uliCookie; /* Spy requires a cookie for revoking */
+ BOOL bDoCount; /* Is it counting? */
+ DWORD dwSkipCount; /* The skipped count */
+ BOOL bUninitializing; /* Is it uninitializing? */
+ DWORD dwUnknown2;
+} IMMTLSDATA, *PIMMTLSDATA;
+
+static VOID
+Imm32InitTLS(VOID)
+{
+ RtlEnterCriticalSection(&gcsImeDpi);
+
+ if (g_dwTLSIndex == -1)
+ g_dwTLSIndex = TlsAlloc();
+
+ RtlLeaveCriticalSection(&gcsImeDpi);
+}
+
+static IMMTLSDATA*
+Imm32AllocateTLS(VOID)
+{
+ IMMTLSDATA *pData;
+
+ if (g_dwTLSIndex == -1)
+ return NULL;
+
+ pData = (IMMTLSDATA*)TlsGetValue(g_dwTLSIndex);
+ if (pData)
+ return pData;
+
+ pData = (IMMTLSDATA*)ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IMMTLSDATA));
+ if (IS_NULL_UNEXPECTEDLY(pData))
+ return NULL;
+
+ if (IS_FALSE_UNEXPECTEDLY(TlsSetValue(g_dwTLSIndex, pData)))
+ {
+ ImmLocalFree(pData);
+ return NULL;
+ }
+
+ return pData;
+}
+
+static IMMTLSDATA*
+Imm32GetTLS(VOID)
+{
+ if (g_dwTLSIndex == -1)
+ return NULL;
+
+ return (IMMTLSDATA*)TlsGetValue(g_dwTLSIndex);
+}
+
+/* Get */
+static DWORD
+Imm32GetCoInitCountSkip(VOID)
+{
+ IMMTLSDATA *pData = Imm32GetTLS();
+ if (!pData)
+ return 0;
+ return pData->dwSkipCount;
+}
+
+/* Increment */
+static DWORD
+Imm32IncCoInitCountSkip(VOID)
+{
+ IMMTLSDATA *pData;
+ DWORD dwOldSkipCount;
+
+ pData = Imm32GetTLS();
+ if (!pData)
+ return 0;
+
+ dwOldSkipCount = pData->dwSkipCount;
+ if (pData->bDoCount)
+ pData->dwSkipCount = dwOldSkipCount + 1;
+
+ return dwOldSkipCount;
+}
+
+/* Decrement */
+static DWORD
+Imm32DecCoInitCountSkip(VOID)
+{
+ DWORD dwSkipCount;
+ IMMTLSDATA *pData;
+
+ pData = Imm32GetTLS();;
+ if (!pData)
+ return 0;
+
+ dwSkipCount = pData->dwSkipCount;
+ if (pData->bDoCount)
+ {
+ if (dwSkipCount)
+ pData->dwSkipCount = dwSkipCount - 1;
+ }
+
+ return dwSkipCount;
+}
+
+/***********************************************************************
+ * CtfImmEnterCoInitCountSkipMode (IMM32.@)
+ */
+VOID WINAPI CtfImmEnterCoInitCountSkipMode(VOID)
+{
+ IMMTLSDATA *pData;
+
+ TRACE("()\n");
+
+ pData = Imm32GetTLS();
+ if (pData)
+ ++(pData->bDoCount);
+}
+
+/***********************************************************************
+ * CtfImmLeaveCoInitCountSkipMode (IMM32.@)
+ */
+BOOL WINAPI CtfImmLeaveCoInitCountSkipMode(VOID)
+{
+ IMMTLSDATA *pData;
+
+ TRACE("()\n");
+
+ pData = Imm32GetTLS();
+ if (!pData || !pData->bDoCount)
+ return FALSE;
+
+ --(pData->bDoCount);
+ return TRUE;
+}
+
+/***********************************************************************
+ * ISPY (I am not spy!)
+ *
+ * ISPY watches CoInitialize[Ex] / CoUninitialize to manage COM initialization status.
+ */
+
+typedef struct ISPY
+{
+ const IInitializeSpyVtbl *m_pSpyVtbl;
+ LONG m_cRefs;
+} ISPY, *PISPY;
+
+static STDMETHODIMP
+ISPY_QueryInterface(
+ _Inout_ IInitializeSpy *pThis,
+ _In_ REFIID riid,
+ _Inout_ LPVOID *ppvObj)
+{
+ ISPY *pSpy = (ISPY*)pThis;
+
+ if (!ppvObj)
+ return E_INVALIDARG;
+
+ *ppvObj = NULL;
+
+ if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid,
&IID_IInitializeSpy))
+ return E_NOINTERFACE;
+
+ ++(pSpy->m_cRefs);
+ *ppvObj = pSpy;
+ return S_OK;
+}
+
+static STDMETHODIMP_(ULONG)
+ISPY_AddRef(
+ _Inout_ IInitializeSpy *pThis)
+{
+ ISPY *pSpy = (ISPY*)pThis;
+ return ++pSpy->m_cRefs;
+}
+
+static STDMETHODIMP_(ULONG)
+ISPY_Release(
+ _Inout_ IInitializeSpy *pThis)
+{
+ ISPY *pSpy = (ISPY*)pThis;
+ if (--pSpy->m_cRefs == 0)
+ {
+ ImmLocalFree(pSpy);
+ return 0;
+ }
+ return pSpy->m_cRefs;
+}
+
+/*
+ * (Pre/Post)(Initialize/Uninitialize) will be automatically called from OLE32
+ * as the results of watching.
+ */
+
+static STDMETHODIMP
+ISPY_PreInitialize(
+ _Inout_ IInitializeSpy *pThis,
+ _In_ DWORD dwCoInit,
+ _In_ DWORD dwCurThreadAptRefs)
+{
+ DWORD cCount;
+
+ UNREFERENCED_PARAMETER(pThis);
+
+ cCount = Imm32IncCoInitCountSkip();
+ if (!dwCoInit &&
+ (dwCurThreadAptRefs == cCount + 1) &&
+ (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT))
+ {
+ Imm32ActivateOrDeactivateTIM(FALSE);
+ CtfImmCoUninitialize();
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP
+ISPY_PostInitialize(
+ _Inout_ IInitializeSpy *pThis,
+ _In_ HRESULT hrCoInit,
+ _In_ DWORD dwCoInit,
+ _In_ DWORD dwNewThreadAptRefs)
+{
+ DWORD CoInitCountSkip;
+
+ UNREFERENCED_PARAMETER(pThis);
+ UNREFERENCED_PARAMETER(dwCoInit);
+
+ CoInitCountSkip = Imm32GetCoInitCountSkip();
+
+ if ((hrCoInit != S_FALSE) ||
+ (dwNewThreadAptRefs != CoInitCountSkip + 2) ||
+ !(GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT))
+ {
+ return hrCoInit;
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP
+ISPY_PreUninitialize(
+ _Inout_ IInitializeSpy *pThis,
+ _In_ DWORD dwCurThreadAptRefs)
+{
+ UNREFERENCED_PARAMETER(pThis);
+
+ if (dwCurThreadAptRefs == 1 &&
+ !RtlDllShutdownInProgress() &&
+ !Imm32InsideLoaderLock() &&
+ (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT))
+ {
+ IMMTLSDATA *pData = Imm32GetTLS();
+ if (pData && !pData->bUninitializing)
+ Imm32CoInitializeEx();
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP
+ISPY_PostUninitialize(
+ _In_ IInitializeSpy *pThis,
+ _In_ DWORD dwNewThreadAptRefs)
+{
+ UNREFERENCED_PARAMETER(pThis);
+ UNREFERENCED_PARAMETER(dwNewThreadAptRefs);
+ Imm32DecCoInitCountSkip();
+ return S_OK;
+}
+
+static const IInitializeSpyVtbl g_vtblISPY =
+{
+ ISPY_QueryInterface,
+ ISPY_AddRef,
+ ISPY_Release,
+ ISPY_PreInitialize,
+ ISPY_PostInitialize,
+ ISPY_PreUninitialize,
+ ISPY_PostUninitialize,
+};
+
+static ISPY*
+Imm32AllocIMMISPY(VOID)
+{
+ ISPY *pSpy = (ISPY*)ImmLocalAlloc(0, sizeof(ISPY));
+ if (!pSpy)
+ return NULL;
+
+ pSpy->m_pSpyVtbl = &g_vtblISPY;
+ pSpy->m_cRefs = 1;
+ return pSpy;
+}
+
+#define Imm32DeleteIMMISPY(pSpy) ImmLocalFree(pSpy)
+
+/***********************************************************************
+ * CtfImmCoInitialize (Not exported)
+ */
+HRESULT
+CtfImmCoInitialize(VOID)
+{
+ HRESULT hr;
+ IMMTLSDATA *pData;
+ ISPY *pSpy;
+
+ if (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT)
+ return S_OK; /* Already initialized */
+
+ hr = Imm32CoInitializeEx();
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr; /* CoInitializeEx failed */
+
+ GetWin32ClientInfo()->CI_flags |= CI_CTFCOINIT;
+ Imm32InitTLS();
+
+ pData = Imm32AllocateTLS();
+ if (!pData || pData->pSpy)
+ return S_OK; /* Cannot allocate or already it has a spy */
+
+ pSpy = Imm32AllocIMMISPY();
+ pData->pSpy = (IInitializeSpy*)pSpy;
+ if (IS_NULL_UNEXPECTEDLY(pSpy))
+ return S_OK; /* Cannot allocate a spy */
+
+ if (FAILED_UNEXPECTEDLY(Imm32CoRegisterInitializeSpy(pData->pSpy,
&pData->uliCookie)))
+ {
+ /* Failed to register the spy */
+ Imm32DeleteIMMISPY(pData->pSpy);
+ pData->pSpy = NULL;
+ pData->uliCookie.QuadPart = 0;
+ }
+
+ return S_OK;
+}
+
+/***********************************************************************
+ * CtfImmCoUninitialize (IMM32.@)
+ */
+VOID WINAPI
+CtfImmCoUninitialize(VOID)
+{
+ IMMTLSDATA *pData;
+
+ if (!(GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT))
+ return; /* Not CoInitialize'd */
+
+ pData = Imm32GetTLS();
+ if (pData)
+ {
+ pData->bUninitializing = TRUE;
+ Imm32CoUninitialize(); /* Do CoUninitialize */
+ pData->bUninitializing = FALSE;
+
+ GetWin32ClientInfo()->CI_flags &= ~CI_CTFCOINIT;
+ }
+
+ pData = Imm32AllocateTLS();
+ if (!pData || !pData->pSpy)
+ return; /* There were no spy */
+
+ /* Our work is done. We don't need spies like you anymore. */
+ Imm32CoRevokeInitializeSpy(pData->uliCookie);
+ ISPY_Release(pData->pSpy);
+ pData->pSpy = NULL;
+ pData->uliCookie.QuadPart = 0;
+}
+
/***********************************************************************
* This function loads the CTF IME file if necessary and establishes
* communication with the CTF IME.
@@ -286,6 +743,8 @@ Imm32LoadCtfIme(VOID)
HRESULT
CtfImeCreateThreadMgr(VOID)
{
+ TRACE("()\n");
+
if (!Imm32LoadCtfIme())
return E_FAIL;
@@ -298,6 +757,8 @@ CtfImeCreateThreadMgr(VOID)
HRESULT
CtfImeDestroyThreadMgr(VOID)
{
+ TRACE("()\n");
+
if (!Imm32LoadCtfIme())
return E_FAIL;
@@ -362,6 +823,8 @@ HRESULT
CtfImeCreateInputContext(
_In_ HIMC hIMC)
{
+ TRACE("(%p)\n", hIMC);
+
if (!Imm32LoadCtfIme())
return E_FAIL;
@@ -374,6 +837,8 @@ CtfImeCreateInputContext(
HRESULT
CtfImeDestroyInputContext(_In_ HIMC hIMC)
{
+ TRACE("(%p)\n", hIMC);
+
if (!Imm32LoadCtfIme())
return E_FAIL;
@@ -394,8 +859,61 @@ Imm32EnumCreateCtfICProc(
}
/***********************************************************************
- * This function calls CtfImeDestroyInputContext if possible.
+ * Thread Input Manager (TIM)
*/
+
+static BOOL
+Imm32IsTIMDisabledInRegistry(VOID)
+{
+ DWORD dwData, cbData;
+ HKEY hKey;
+ LSTATUS error;
+
+ error = RegOpenKeyW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF",
&hKey);
+ if (error != ERROR_SUCCESS)
+ return FALSE;
+
+ dwData = 0;
+ cbData = sizeof(dwData);
+ RegQueryValueExW(hKey, L"Disable Thread Input Manager", NULL, NULL,
(LPBYTE)&dwData, &cbData);
+ RegCloseKey(hKey);
+ return !!dwData;
+}
+
+HRESULT
+Imm32ActivateOrDeactivateTIM(
+ _In_ BOOL bCreate)
+{
+ HRESULT hr = S_OK;
+
+ if (!IS_CICERO_MODE() || IS_16BIT_MODE() ||
+ !(GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT))
+ {
+ return S_OK; /* No need to activate/de-activate TIM */
+ }
+
+ if (bCreate)
+ {
+ if (!(GetWin32ClientInfo()->CI_flags & CI_CTFTIM))
+ {
+ hr = CtfImeCreateThreadMgr();
+ if (SUCCEEDED(hr))
+ GetWin32ClientInfo()->CI_flags |= CI_CTFTIM;
+ }
+ }
+ else /* Destroy */
+ {
+ if (GetWin32ClientInfo()->CI_flags & CI_CTFTIM)
+ {
+ hr = CtfImeDestroyThreadMgr();
+ if (SUCCEEDED(hr))
+ GetWin32ClientInfo()->CI_flags &= ~CI_CTFTIM;
+ }
+ }
+
+ return hr;
+}
+
HRESULT
CtfImmTIMDestroyInputContext(
_In_ HIMC hIMC)
@@ -422,34 +940,34 @@ CtfImmTIMCreateInputContext(
if (GetWin32ClientInfo()->CI_flags & CI_AIMMACTIVATED)
{
- if (!pClientImc->bUnknown4)
+ if (!pClientImc->bCtfIme)
{
dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
dwCurrentThreadId = GetCurrentThreadId();
if (dwImeThreadId == dwCurrentThreadId)
{
- pClientImc->bUnknown4 = 1;
+ pClientImc->bCtfIme = TRUE;
hr = CtfImeCreateInputContext(hIMC);
- if (FAILED(hr))
- pClientImc->bUnknown4 = 0;
+ if (FAILED_UNEXPECTEDLY(hr))
+ pClientImc->bCtfIme = FALSE;
}
}
}
else
{
- if (!(GetWin32ClientInfo()->CI_flags & 0x100))
+ if (!(GetWin32ClientInfo()->CI_flags & CI_CTFTIM))
return S_OK;
- if (!pClientImc->bUnknown4)
+ if (!pClientImc->bCtfIme)
{
dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
dwCurrentThreadId = GetCurrentThreadId();
if ((dwImeThreadId == dwCurrentThreadId) && IS_CICERO_MODE()
&& !IS_16BIT_MODE())
{
- pClientImc->bUnknown4 = 1;
+ pClientImc->bCtfIme = TRUE;
hr = CtfImeCreateInputContext(hIMC);
- if (FAILED(hr))
- pClientImc->bUnknown4 = 0;
+ if (FAILED_UNEXPECTEDLY(hr))
+ pClientImc->bCtfIme = FALSE;
}
}
}
@@ -458,6 +976,19 @@ CtfImmTIMCreateInputContext(
return hr;
}
+/***********************************************************************
+ * CtfImmLastEnabledWndDestroy (IMM32.@)
+ *
+ * Same as Imm32ActivateOrDeactivateTIM but its naming is improper.
+ */
+HRESULT WINAPI
+CtfImmLastEnabledWndDestroy(
+ _In_ BOOL bCreate)
+{
+ TRACE("(%d)\n", bCreate);
+ return Imm32ActivateOrDeactivateTIM(bCreate);
+}
+
/***********************************************************************
* CtfAImmActivate (IMM32.@)
*
@@ -529,7 +1060,7 @@ CtfImmIsCiceroEnabled(VOID)
}
/***********************************************************************
- * CtfImmIsTextFrameServiceDisabled(IMM32.@)
+ * CtfImmIsTextFrameServiceDisabled (IMM32.@)
*
* @return TRUE if TSF is disabled.
*/
@@ -540,17 +1071,123 @@ CtfImmIsTextFrameServiceDisabled(VOID)
}
/***********************************************************************
- * CtfImmTIMActivate(IMM32.@)
+ * ImmDisableTextFrameService (IMM32.@)
+ */
+BOOL WINAPI
+ImmDisableTextFrameService(_In_ DWORD dwThreadId)
+{
+ HRESULT hr = S_OK;
+
+ TRACE("(0x%lX)\n", dwThreadId);
+
+ if (dwThreadId == -1)
+ g_disable_CUAS_flag = TRUE;
+
+ if ((dwThreadId && !g_disable_CUAS_flag) ||
(GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED))
+ return TRUE;
+
+ GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
+
+ if (IS_CICERO_MODE() && !IS_16BIT_MODE() &&
+ (GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT) &&
+ (GetWin32ClientInfo()->CI_flags & CI_CTFTIM))
+ {
+ hr = CtfImeDestroyThreadMgr();
+ if (SUCCEEDED(hr))
+ {
+ GetWin32ClientInfo()->CI_flags &= ~CI_CTFTIM;
+ CtfImmCoUninitialize();
+ }
+ }
+
+ return hr == S_OK;
+}
+
+/***********************************************************************
+ * CtfImmTIMActivate (IMM32.@)
+ *
+ * Activates Thread Input Manager (TIM) in the thread.
*/
HRESULT WINAPI
CtfImmTIMActivate(_In_ HKL hKL)
{
- FIXME("(%p)\n", hKL);
- return E_NOTIMPL;
+ HRESULT hr = S_OK;
+
+ TRACE("(%p)\n", hKL);
+
+ if (g_disable_CUAS_flag)
+ {
+ TRACE("g_disable_CUAS_flag\n");
+ GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
+ return FALSE;
+ }
+
+ if (GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED)
+ {
+ TRACE("CI_TSFDISABLED\n");
+ return FALSE;
+ }
+
+ if (Imm32IsTIMDisabledInRegistry())
+ {
+ TRACE("TIM is disabled in registry\n");
+ GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
+ return FALSE;
+ }
+
+ if (!Imm32IsInteractiveUserLogon() || Imm32IsRunningInMsoobe())
+ {
+ TRACE("TIM is disabled due to LOGON or MSOBE\n");
+ return FALSE;
+ }
+
+ if (!Imm32IsCUASEnabledInRegistry())
+ {
+ TRACE("CUAS is disabled in registry\n");
+ GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
+ return FALSE;
+ }
+
+ if (NtCurrentTeb()->ProcessEnvironmentBlock->AppCompatFlags.LowPart &
0x100)
+ {
+ TRACE("CUAS is disabled by AppCompatFlags\n");
+ GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
+ return FALSE;
+ }
+
+ if (RtlIsThreadWithinLoaderCallout() || Imm32InsideLoaderLock())
+ {
+ TRACE("TIM is disabled by Loader\n");
+ return FALSE;
+ }
+
+ if (!IS_CICERO_MODE() || IS_16BIT_MODE())
+ {
+ TRACE("TIM is disabled because CICERO mode is unset\n");
+ return FALSE;
+ }
+
+ if (IS_IME_HKL(hKL))
+ hKL = (HKL)UlongToHandle(MAKELONG(LOWORD(hKL), LOWORD(hKL)));
+
+ if (!ImmLoadIME(hKL))
+ Imm32TF_InvalidAssemblyListCacheIfExist();
+
+ CtfImmCoInitialize();
+
+ if ((GetWin32ClientInfo()->CI_flags & CI_CTFCOINIT) &&
+ !(GetWin32ClientInfo()->CI_flags & CI_CTFTIM))
+ {
+ hr = CtfImeCreateThreadMgr();
+ if (SUCCEEDED(hr))
+ GetWin32ClientInfo()->CI_flags |= CI_CTFTIM;
+ }
+
+ return hr;
}
/***********************************************************************
- * CtfImmGenerateMessage(IMM32.@)
+ * CtfImmGenerateMessage (IMM32.@)
*/
BOOL WINAPI
CtfImmGenerateMessage(
@@ -638,7 +1275,7 @@ CtfImmGenerateMessage(
}
/***********************************************************************
- * CtfImmHideToolbarWnd(IMM32.@)
+ * CtfImmHideToolbarWnd (IMM32.@)
*
* Used with CtfImmRestoreToolbarWnd.
*/
@@ -667,7 +1304,7 @@ CtfImmHideToolbarWnd(VOID)
}
/***********************************************************************
- * CtfImmRestoreToolbarWnd(IMM32.@)
+ * CtfImmRestoreToolbarWnd (IMM32.@)
*
* Used with CtfImmHideToolbarWnd.
*/
@@ -684,7 +1321,7 @@ CtfImmRestoreToolbarWnd(
TRACE("(%p, 0x%X)\n", pUnused, dwShowFlags);
hr = Imm32TF_CreateLangBarMgr(&pBarMgr);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return;
if (dwShowFlags)
@@ -693,20 +1330,8 @@ CtfImmRestoreToolbarWnd(
pBarMgr->lpVtbl->Release(pBarMgr);
}
-BOOL Imm32InsideLoaderLock(VOID)
-{
- return (NtCurrentTeb()->ProcessEnvironmentBlock->LoaderLock->OwningThread
==
- NtCurrentTeb()->ClientId.UniqueThread);
-}
-
-/* FIXME: Use RTL */
-BOOL WINAPI RtlDllShutdownInProgress(VOID)
-{
- return FALSE;
-}
-
/***********************************************************************
- * CtfImmDispatchDefImeMessage(IMM32.@)
+ * CtfImmDispatchDefImeMessage (IMM32.@)
*/
LRESULT WINAPI
CtfImmDispatchDefImeMessage(
@@ -724,7 +1349,7 @@ CtfImmDispatchDefImeMessage(
}
/***********************************************************************
- * CtfImmIsGuidMapEnable(IMM32.@)
+ * CtfImmIsGuidMapEnable (IMM32.@)
*/
BOOL WINAPI
CtfImmIsGuidMapEnable(
@@ -757,7 +1382,7 @@ CtfImmIsGuidMapEnable(
}
/***********************************************************************
- * CtfImmGetGuidAtom(IMM32.@)
+ * CtfImmGetGuidAtom (IMM32.@)
*/
HRESULT WINAPI
CtfImmGetGuidAtom(
diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c
index 39d4cd3b1ef..5723fde1a59 100644
--- a/dll/win32/imm32/imm.c
+++ b/dll/win32/imm32/imm.c
@@ -1103,15 +1103,6 @@ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
return TRUE; // Do nothing. This is correct.
}
-/***********************************************************************
-* ImmDisableTextFrameService(IMM32.@)
-*/
-BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
-{
- FIXME("Stub\n");
- return FALSE;
-}
-
/***********************************************************************
* ImmEnumInputContext(IMM32.@)
*/
diff --git a/dll/win32/imm32/imm32.spec b/dll/win32/imm32/imm32.spec
index 14044ca710b..2e84d6a143c 100644
--- a/dll/win32/imm32/imm32.spec
+++ b/dll/win32/imm32/imm32.spec
@@ -1,7 +1,9 @@
@ stdcall CtfAImmActivate(ptr)
@ stdcall CtfAImmDeactivate(long)
@ stdcall CtfAImmIsIME(ptr)
+@ stdcall CtfImmCoUninitialize()
@ stdcall CtfImmDispatchDefImeMessage(ptr long ptr ptr)
+@ stdcall CtfImmEnterCoInitCountSkipMode()
@ stdcall CtfImmGenerateMessage(ptr long)
@ stdcall CtfImmGetGuidAtom(ptr long ptr)
@ stdcall CtfImmHideToolbarWnd()
@@ -9,6 +11,8 @@
@ stdcall CtfImmIsCiceroStartedInThread()
@ stdcall CtfImmIsGuidMapEnable(ptr)
@ stdcall CtfImmIsTextFrameServiceDisabled()
+@ stdcall CtfImmLastEnabledWndDestroy(long)
+@ stdcall CtfImmLeaveCoInitCountSkipMode()
@ stdcall CtfImmRestoreToolbarWnd(ptr long)
@ stdcall CtfImmSetAppCompatFlags(long)
@ stdcall CtfImmSetCiceroStartInThread(long)
diff --git a/dll/win32/imm32/precomp.h b/dll/win32/imm32/precomp.h
index 8fc4b27d4b7..3f667d1d6f5 100644
--- a/dll/win32/imm32/precomp.h
+++ b/dll/win32/imm32/precomp.h
@@ -112,12 +112,17 @@ BOOL WINAPI Imm32IsImcAnsi(HIMC hIMC);
* --- Examine the condition, and then generate trace log if necessary.
*/
#ifdef NDEBUG /* on Release */
+#define FAILED_UNEXPECTEDLY(hr) (FAILED(hr))
#define IS_NULL_UNEXPECTEDLY(p) (!(p))
#define IS_ZERO_UNEXPECTEDLY(p) (!(p))
#define IS_TRUE_UNEXPECTEDLY(x) (x)
#define IS_FALSE_UNEXPECTEDLY(x) (!(x))
#define IS_ERROR_UNEXPECTEDLY(x) (!(x))
#else /* on Debug */
+#define FAILED_UNEXPECTEDLY(hr) \
+ (FAILED(hr) ? (ros_dbg_log(__WINE_DBCL_ERR, __wine_dbch___default, \
+ __FILE__, __FUNCTION__, __LINE__, "FAILED(%s)\n", #hr),
UNEXPECTED(), TRUE) \
+ : FALSE)
#define IS_NULL_UNEXPECTEDLY(p) \
(!(p) ? (ros_dbg_log(__WINE_DBCL_ERR, __wine_dbch___default, \
__FILE__, __FUNCTION__, __LINE__, "%s was NULL\n",
#p), UNEXPECTED(), TRUE) \
@@ -192,3 +197,7 @@ BOOL Imm32StoreBitmapToBytes(HBITMAP hbm, LPBYTE pbData, DWORD
cbDataMax);
HRESULT CtfImmTIMCreateInputContext(_In_ HIMC hIMC);
HRESULT CtfImmTIMDestroyInputContext(_In_ HIMC hIMC);
+HRESULT CtfImmCoInitialize(VOID);
+HRESULT CtfImeCreateThreadMgr(VOID);
+HRESULT CtfImeDestroyThreadMgr(VOID);
+HRESULT Imm32ActivateOrDeactivateTIM(_In_ BOOL bCreate);
diff --git a/sdk/include/ddk/immdev.h b/sdk/include/ddk/immdev.h
index b553838888f..e36ff688666 100644
--- a/sdk/include/ddk/immdev.h
+++ b/sdk/include/ddk/immdev.h
@@ -17,6 +17,8 @@
extern "C" {
#endif
+BOOL WINAPI ImmDisableTextFrameService(_In_ DWORD dwThreadId);
+
typedef struct tagSOFTKBDDATA
{
UINT uCount;
@@ -317,7 +319,7 @@ typedef struct tagCLIENTIMC
RTL_CRITICAL_SECTION cs;
UINT uCodePage;
HKL hKL;
- BOOL bUnknown4;
+ BOOL bCtfIme;
} CLIENTIMC, *PCLIENTIMC;
#ifndef _WIN64
diff --git a/sdk/include/reactos/imm32_undoc.h b/sdk/include/reactos/imm32_undoc.h
index 28039bcb857..08be32a2dcd 100644
--- a/sdk/include/reactos/imm32_undoc.h
+++ b/sdk/include/reactos/imm32_undoc.h
@@ -31,6 +31,10 @@ VOID WINAPI CtfImmSetAppCompatFlags(_In_ DWORD dwFlags);
DWORD WINAPI CtfImmHideToolbarWnd(VOID);
VOID WINAPI CtfImmRestoreToolbarWnd(_In_ LPVOID pUnused, _In_ DWORD dwShowFlags);
BOOL WINAPI CtfImmGenerateMessage(_In_ HIMC hIMC, _In_ BOOL bSend);
+VOID WINAPI CtfImmCoUninitialize(VOID);
+VOID WINAPI CtfImmEnterCoInitCountSkipMode(VOID);
+BOOL WINAPI CtfImmLeaveCoInitCountSkipMode(VOID);
+HRESULT WINAPI CtfImmLastEnabledWndDestroy(_In_ BOOL bCreate);
LRESULT WINAPI
CtfImmDispatchDefImeMessage(
diff --git a/win32ss/include/ntuser.h b/win32ss/include/ntuser.h
index f501babb00a..2763b4b24cc 100644
--- a/win32ss/include/ntuser.h
+++ b/win32ss/include/ntuser.h
@@ -303,6 +303,8 @@ typedef struct _CALLBACKWND
#define CI_CURTHPRHOOK 0x00000010
#define CI_CLASSESREGISTERED 0x00000020
#define CI_IMMACTIVATE 0x00000040 /* IMM/IME (Asian input) */
+#define CI_CTFCOINIT 0x00000080 /* Did CTF CoInitialize? */
+#define CI_CTFTIM 0x00000100 /* CTF Thread Input Manager (TIM) */
#define CI_TSFDISABLED 0x00000400 /* TSF (Text Services Framework a.k.a. Cicero)
*/
#define CI_AIMMACTIVATED 0x00000800 /* Active IMM (AIMM) */