[IMM32][SDK][NTUSER] Implement CtfImmTIMActivate (#6041)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Thu, 30 Nov 2023 08:22:50 +0000 (17:22 +0900)
committerGitHub <noreply@github.com>
Thu, 30 Nov 2023 08:22:50 +0000 (17:22 +0900)
- 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
dll/win32/imm32/ctf.c
dll/win32/imm32/imm.c
dll/win32/imm32/imm32.spec
dll/win32/imm32/precomp.h
sdk/include/ddk/immdev.h
sdk/include/reactos/imm32_undoc.h
win32ss/include/ntuser.h

index b765ec1..60b146b 100644 (file)
@@ -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)
index dd325d4..be1853f 100644 (file)
@@ -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(
index 39d4cd3..5723fde 100644 (file)
@@ -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.@)
  */
index 14044ca..2e84d6a 100644 (file)
@@ -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)
index 8fc4b27..3f667d1 100644 (file)
@@ -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);
index b553838..e36ff68 100644 (file)
@@ -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
index 28039bc..08be32a 100644 (file)
@@ -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(
index f501bab..2763b4b 100644 (file)
@@ -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) */