https://git.reactos.org/?p=reactos.git;a=commitdiff;h=980ebf0694960551201fdd132e0ec2475a9433fd

commit 980ebf0694960551201fdd132e0ec2475a9433fd
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Fri Feb 23 17:43:13 2024 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Fri Feb 23 17:43:13 2024 +0900

    [MSCTFIME] Implement CtfImeSetActiveContextAlways (#6522)
    
    Supporting TIPs...
    JIRA issue: CORE-19360
    - Move code of functions.cpp
      into misc.cpp and delete functions.cpp.
    - Add implementation to
      CicBridge::GetDocumentManager,
      CicBridge::CreateInputContext, and
      CicBridge::SetActiveContextAlways
      methods.
    - Implement NotifyIME,
      CtfImeSetActiveContextAlways, and
      CtfImeCreateInputContext functions.
---
 dll/ime/msctfime/CMakeLists.txt |   4 -
 dll/ime/msctfime/bridge.cpp     | 153 ++++++++++----
 dll/ime/msctfime/bridge.h       |  21 +-
 dll/ime/msctfime/functions.cpp  | 261 ------------------------
 dll/ime/msctfime/functions.h    |  63 ------
 dll/ime/msctfime/misc.cpp       | 438 ++++++++++++++++++++++++++++++++++++++--
 dll/ime/msctfime/misc.h         |  68 ++++++-
 dll/ime/msctfime/msctfime.cpp   | 211 ++++++-------------
 dll/ime/msctfime/msctfime.h     |  16 +-
 dll/ime/msctfime/tls.cpp        |  32 +++
 dll/ime/msctfime/tls.h          |  44 +---
 dll/ime/msctfime/ui.cpp         |   2 +-
 dll/ime/msctfime/ui.h           |   2 -
 13 files changed, 725 insertions(+), 590 deletions(-)

diff --git a/dll/ime/msctfime/CMakeLists.txt b/dll/ime/msctfime/CMakeLists.txt
index 0e5acc805b0..717e879e119 100644
--- a/dll/ime/msctfime/CMakeLists.txt
+++ b/dll/ime/msctfime/CMakeLists.txt
@@ -1,12 +1,8 @@
 
-include_directories(
-    ${REACTOS_SOURCE_DIR}/win32ss/include)
-
 spec2def(msctfime.ime msctfime.spec)
 
 list(APPEND SOURCE
     bridge.cpp
-    functions.cpp
     inputcontext.cpp
     misc.cpp
     msctfime.cpp
diff --git a/dll/ime/msctfime/bridge.cpp b/dll/ime/msctfime/bridge.cpp
index 50ac6622614..cd966083264 100644
--- a/dll/ime/msctfime/bridge.cpp
+++ b/dll/ime/msctfime/bridge.cpp
@@ -1,7 +1,7 @@
 /*
  * PROJECT:     ReactOS msctfime.ime
  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
- * PURPOSE:     Bridge
+ * PURPOSE:     The bridge of msctfime.ime
  * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
  */
 
@@ -65,22 +65,19 @@ CicBridge::~CicBridge()
         UnInitIMMX(pTLS);
 }
 
-void CicBridge::GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& 
imeContext)
+/// @implemented
+ITfDocumentMgr*
+CicBridge::GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& imeContext)
 {
     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
-    if (pCicIC)
-    {
-        m_pDocMgr = pCicIC->m_pDocumentMgr;
-        m_pDocMgr->AddRef();
-    }
-    else
-    {
-        m_pDocMgr->Release();
-        m_pDocMgr = NULL;
-    }
+    if (!pCicIC)
+        return NULL;
+
+    pCicIC->m_pDocumentMgr->AddRef();
+    return pCicIC->m_pDocumentMgr;
 }
 
-/// @unimplemented
+/// @implemented
 HRESULT
 CicBridge::CreateInputContext(
     _Inout_ TLS *pTLS,
@@ -100,45 +97,49 @@ CicBridge::CreateInputContext(
 
     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+    if (pCicIC)
+        return S_OK;
+
+    pCicIC = new(cicNoThrow) CicInputContext(m_cliendId, &m_LibThread, hIMC);
     if (!pCicIC)
     {
-        pCicIC = new(cicNoThrow) CicInputContext(m_cliendId, &m_LibThread, 
hIMC);
-        if (!pCicIC)
-        {
-            imeContext.unlock();
-            imcLock.unlock();
-            DestroyInputContext(pTLS, hIMC);
-            return E_OUTOFMEMORY;
-        }
-
-        if (!pTLS->m_pThreadMgr)
-        {
-            pCicIC->Release();
-            imeContext.unlock();
-            imcLock.unlock();
-            DestroyInputContext(pTLS, hIMC);
-            return E_NOINTERFACE;
-        }
+        imeContext.unlock();
+        imcLock.unlock();
+        DestroyInputContext(pTLS, hIMC);
+        return E_OUTOFMEMORY;
+    }
 
-        imeContext.get().m_pCicIC = pCicIC;
+    if (!pTLS->m_pThreadMgr)
+    {
+        pCicIC->Release();
+        imeContext.unlock();
+        imcLock.unlock();
+        DestroyInputContext(pTLS, hIMC);
+        return E_NOINTERFACE;
     }
 
+    imeContext.get().m_pCicIC = pCicIC;
+
     HRESULT hr = pCicIC->CreateInputContext(pTLS->m_pThreadMgr, imcLock);
     if (FAILED(hr))
     {
         pCicIC->Release();
         imeContext.get().m_pCicIC = NULL;
+        return hr;
     }
-    else
+
+    HWND hWnd = imcLock.get().hWnd;
+    if (hWnd && hWnd == ::GetFocus())
     {
-        if (imcLock.get().hWnd && imcLock.get().hWnd == ::GetFocus())
+        ITfDocumentMgr *pDocMgr = GetDocumentManager(imeContext);
+        if (pDocMgr)
         {
-            GetDocumentManager(imeContext);
-            //FIXME
+            SetAssociate(pTLS, hWnd, hIMC, pTLS->m_pThreadMgr, pDocMgr);
+            pDocMgr->Release();
         }
     }
 
-    return E_NOTIMPL;
+    return hr;
 }
 
 /// @implemented
@@ -608,3 +609,83 @@ CicBridge::ConfigureRegisterWord(
     pFunction->Release();
     return hr;
 }
+
+/// @unimplemented
+void CicBridge::SetAssociate(
+    TLS *pTLS,
+    HWND hWnd,
+    HIMC hIMC,
+    ITfThreadMgr_P *pThreadMgr,
+    ITfDocumentMgr *pDocMgr)
+{
+    //FIXME
+}
+
+HRESULT
+CicBridge::SetActiveContextAlways(TLS *pTLS, HIMC hIMC, BOOL fActive, HWND 
hWnd, HKL hKL)
+{
+    auto pThreadMgr = pTLS->m_pThreadMgr;
+    if (!pThreadMgr)
+        return E_OUTOFMEMORY;
+
+    if (fActive)
+    {
+        if (!hIMC)
+        {
+            SetAssociate(pTLS, hWnd, hIMC, pThreadMgr, m_pDocMgr);
+            return S_OK;
+        }
+
+        CicIMCLock imcLock(hIMC);
+        if (FAILED(imcLock.m_hr))
+            return imcLock.m_hr;
+
+        CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+        if (FAILED(imeContext.m_hr))
+            return imeContext.m_hr;
+
+        if (hIMC == ::ImmGetContext(hWnd))
+        {
+            ITfDocumentMgr *pDocMgr = GetDocumentManager(imeContext);
+            if (pDocMgr)
+            {
+                SetAssociate(pTLS, imcLock.get().hWnd, hIMC, pThreadMgr, 
pDocMgr);
+                pDocMgr->Release();
+            }
+        }
+
+        return S_OK;
+    }
+
+    if (hIMC && !IsEALang(LOWORD(hKL)))
+    {
+        CicIMCLock imcLock(hIMC);
+        if (FAILED(imcLock.m_hr))
+            return imcLock.m_hr;
+
+        CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+        if (FAILED(imeContext.m_hr))
+            return imeContext.m_hr;
+
+        CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+        if (!pCicIC->m_dwUnknown6_5[2] && !pCicIC->m_dwUnknown6_5[3])
+            ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
+    }
+
+    if (!hIMC || (::GetFocus() != hWnd) || (hIMC != ::ImmGetContext(hWnd)))
+        SetAssociate(pTLS, hWnd, hIMC, pThreadMgr, m_pDocMgr);
+
+    return S_OK;
+}
+
+/// @unimplemented
+HRESULT CicBridge::Notify(
+    TLS *pTLS,
+    ITfThreadMgr *pThreadMgr,
+    HIMC hIMC,
+    DWORD dwAction,
+    DWORD dwIndex,
+    DWORD_PTR dwValue)
+{
+    return E_NOTIMPL; // FIXME
+}
diff --git a/dll/ime/msctfime/bridge.h b/dll/ime/msctfime/bridge.h
index c8b8441203d..fa3919f6953 100644
--- a/dll/ime/msctfime/bridge.h
+++ b/dll/ime/msctfime/bridge.h
@@ -1,7 +1,7 @@
 /*
  * PROJECT:     ReactOS msctfime.ime
  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
- * PURPOSE:     Bridge
+ * PURPOSE:     The bridge of msctfime.ime
  * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
  */
 
@@ -64,7 +64,7 @@ public:
         CicInputContext *pCicIC);
 
     void PostTransMsg(_In_ HWND hWnd, _In_ INT cTransMsgs, _In_ const TRANSMSG 
*pTransMsgs);
-    void GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& imeContext);
+    ITfDocumentMgr* GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& 
imeContext);
 
     HRESULT
     ConfigureGeneral(_Inout_ TLS* pTLS,
@@ -77,4 +77,21 @@ public:
         _In_ HKL hKL,
         _In_ HWND hWnd,
         _Inout_opt_ LPVOID lpData);
+
+    HRESULT SetActiveContextAlways(TLS *pTLS, HIMC hIMC, BOOL fActive, HWND 
hWnd, HKL hKL);
+
+    void SetAssociate(
+        TLS *pTLS,
+        HWND hWnd,
+        HIMC hIMC,
+        ITfThreadMgr_P *pThreadMgr,
+        ITfDocumentMgr *pDocMgr);
+
+    HRESULT Notify(
+        TLS *pTLS,
+        ITfThreadMgr *pThreadMgr,
+        HIMC hIMC,
+        DWORD dwAction,
+        DWORD dwIndex,
+        DWORD_PTR dwValue);
 };
diff --git a/dll/ime/msctfime/functions.cpp b/dll/ime/msctfime/functions.cpp
deleted file mode 100644
index e3133022023..00000000000
--- a/dll/ime/msctfime/functions.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * PROJECT:     ReactOS msctfime.ime
- * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
- * PURPOSE:     The functionalities of msctfime.ime
- * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
- */
-
-#include "msctfime.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
-
-/// @implemented
-CFunctionProviderBase::CFunctionProviderBase(_In_ TfClientId clientId)
-{
-    m_clientId = clientId;
-    m_guid = GUID_NULL;
-    m_bstr = NULL;
-    m_cRefs = 1;
-}
-
-/// @implemented
-CFunctionProviderBase::~CFunctionProviderBase()
-{
-    if (!DllShutdownInProgress())
-        ::SysFreeString(m_bstr);
-}
-
-/// @implemented
-BOOL
-CFunctionProviderBase::Init(
-    _In_ REFGUID rguid,
-    _In_ LPCWSTR psz)
-{
-    m_bstr = ::SysAllocString(psz);
-    m_guid = rguid;
-    return (m_bstr != NULL);
-}
-
-/// @implemented
-STDMETHODIMP
-CFunctionProviderBase::QueryInterface(
-    _In_ REFIID riid,
-    _Out_ LPVOID* ppvObj)
-{
-    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, 
IID_ITfFunctionProvider))
-    {
-        *ppvObj = this;
-        AddRef();
-        return S_OK;
-    }
-    return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFunctionProviderBase::AddRef()
-{
-    return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFunctionProviderBase::Release()
-{
-    if (::InterlockedDecrement(&m_cRefs) == 0)
-    {
-        delete this;
-        return 0;
-    }
-    return m_cRefs;
-}
-
-/// @implemented
-STDMETHODIMP CFunctionProviderBase::GetType(_Out_ GUID *guid)
-{
-    *guid = m_guid;
-    return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP CFunctionProviderBase::GetDescription(_Out_ BSTR *desc)
-{
-    *desc = ::SysAllocString(m_bstr);
-    return (*desc ? S_OK : E_OUTOFMEMORY);
-}
-
-/***********************************************************************/
-
-/// @implemented
-CFunctionProvider::CFunctionProvider(_In_ TfClientId clientId) : 
CFunctionProviderBase(clientId)
-{
-    Init(CLSID_CAImmLayer, L"MSCTFIME::Function Provider");
-}
-
-/// @implemented
-STDMETHODIMP
-CFunctionProvider::GetFunction(
-    _In_ REFGUID guid,
-    _In_ REFIID riid,
-    _Out_ IUnknown **func)
-{
-    *func = NULL;
-
-    if (IsEqualGUID(guid, GUID_NULL) &&
-        IsEqualIID(riid, IID_IAImmFnDocFeed))
-    {
-        *func = new(cicNoThrow) CFnDocFeed();
-        if (*func)
-            return S_OK;
-    }
-
-    return E_NOINTERFACE;
-}
-
-/***********************************************************************/
-
-CFnDocFeed::CFnDocFeed()
-{
-    m_cRefs = 1;
-}
-
-CFnDocFeed::~CFnDocFeed()
-{
-}
-
-/// @implemented
-STDMETHODIMP CFnDocFeed::QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj)
-{
-    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAImmFnDocFeed))
-    {
-        *ppvObj = this;
-        AddRef();
-        return S_OK;
-    }
-    return E_NOINTERFACE;
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFnDocFeed::AddRef()
-{
-    return ::InterlockedIncrement(&m_cRefs);
-}
-
-/// @implemented
-STDMETHODIMP_(ULONG) CFnDocFeed::Release()
-{
-    if (::InterlockedDecrement(&m_cRefs) == 0)
-    {
-        delete this;
-        return 0;
-    }
-    return m_cRefs;
-}
-
-/// @implemented
-STDMETHODIMP CFnDocFeed::DocFeed()
-{
-    TLS *pTLS = TLS::GetTLS();
-    if (!pTLS)
-        return E_OUTOFMEMORY;
-
-    HIMC hIMC = GetActiveContext();
-    CicIMCLock imcLock(hIMC);
-    if (FAILED(imcLock.m_hr))
-        return imcLock.m_hr;
-
-    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
-    if (FAILED(imeContext.m_hr))
-        return imeContext.m_hr;
-    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
-    if (!pCicIC)
-        return E_FAIL;
-
-    UINT uCodePage = CP_ACP;
-    pTLS->m_pProfile->GetCodePageA(&uCodePage);
-    pCicIC->SetupDocFeedString(imcLock, uCodePage);
-    return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP CFnDocFeed::ClearDocFeedBuffer()
-{
-    if (!TLS::GetTLS())
-        return E_OUTOFMEMORY;
-
-    HIMC hIMC = GetActiveContext();
-    CicIMCLock imcLock(hIMC);
-    if (FAILED(imcLock.m_hr))
-        return imcLock.m_hr;
-
-    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
-    if (FAILED(imeContext.m_hr))
-        return imeContext.m_hr;
-
-    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
-    if (!pCicIC)
-        return E_FAIL;
-
-    pCicIC->EscbClearDocFeedBuffer(imcLock, TRUE);
-    return S_OK;
-}
-
-/// @unimplemented
-STDMETHODIMP CFnDocFeed::StartReconvert()
-{
-    TLS *pTLS = TLS::GetTLS();
-    if (!pTLS)
-        return E_OUTOFMEMORY;
-    auto *pThreadMgr = pTLS->m_pThreadMgr;
-    if (!pThreadMgr)
-        return E_OUTOFMEMORY;
-
-    HIMC hIMC = GetActiveContext();
-    CicIMCLock imcLock(hIMC);
-    if (FAILED(imcLock.m_hr))
-        return imcLock.m_hr;
-
-    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
-    if (FAILED(imeContext.m_hr))
-        return imeContext.m_hr;
-    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
-    if (!pCicIC)
-        return E_FAIL;
-
-    UINT uCodePage = CP_ACP;
-    pTLS->m_pProfile->GetCodePageA(&uCodePage);
-
-    pCicIC->m_bReconverting = TRUE;
-    pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, 0, 0);
-    pCicIC->EndReconvertString(imcLock);
-    pCicIC->m_bReconverting = FALSE;
-    return S_OK;
-}
-
-/// @implemented
-STDMETHODIMP CFnDocFeed::StartUndoCompositionString()
-{
-    TLS *pTLS = TLS::GetTLS();
-    if (!pTLS)
-        return E_OUTOFMEMORY;
-    auto *pThreadMgr = pTLS->m_pThreadMgr;
-    if (!pThreadMgr)
-        return E_OUTOFMEMORY;
-
-    HIMC hIMC = GetActiveContext();
-    CicIMCLock imcLock(hIMC);
-    if (FAILED(imcLock.m_hr))
-        return imcLock.m_hr;
-
-    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
-    if (FAILED(imeContext.m_hr))
-        return imeContext.m_hr;
-    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
-    if (!pCicIC)
-        return E_FAIL;
-
-    UINT uCodePage = CP_ACP;
-    pTLS->m_pProfile->GetCodePageA(&uCodePage);
-
-    pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, 0, TRUE);
-    pCicIC->EndReconvertString(imcLock);
-    return S_OK;
-}
diff --git a/dll/ime/msctfime/functions.h b/dll/ime/msctfime/functions.h
deleted file mode 100644
index d0b7d8c2ebe..00000000000
--- a/dll/ime/msctfime/functions.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * PROJECT:     ReactOS msctfime.ime
- * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
- * PURPOSE:     The functionalities of msctfime.ime
- * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
- */
-
-class CFunctionProviderBase : public ITfFunctionProvider
-{
-protected:
-    TfClientId m_clientId;
-    GUID m_guid;
-    BSTR m_bstr;
-    LONG m_cRefs;
-
-public:
-    CFunctionProviderBase(_In_ TfClientId clientId);
-    virtual ~CFunctionProviderBase();
-
-    // IUnknown interface
-    STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) 
override;
-    STDMETHODIMP_(ULONG) AddRef() override;
-    STDMETHODIMP_(ULONG) Release() override;
-
-    // ITfFunctionProvider interface
-    STDMETHODIMP GetType(_Out_ GUID *guid) override;
-    STDMETHODIMP GetDescription(_Out_ BSTR *desc) override;
-    //STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ 
IUnknown **func) = 0;
-
-    BOOL Init(_In_ REFGUID rguid, _In_ LPCWSTR psz);
-};
-
-/***********************************************************************/
-
-class CFunctionProvider : public CFunctionProviderBase
-{
-public:
-    CFunctionProvider(_In_ TfClientId clientId);
-
-    STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ 
IUnknown **func) override;
-};
-
-/***********************************************************************/
-
-class CFnDocFeed : public IAImmFnDocFeed
-{
-    LONG m_cRefs;
-
-public:
-    CFnDocFeed();
-    virtual ~CFnDocFeed();
-
-    // IUnknown interface
-    STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) 
override;
-    STDMETHODIMP_(ULONG) AddRef() override;
-    STDMETHODIMP_(ULONG) Release() override;
-
-    // IAImmFnDocFeed interface
-    STDMETHODIMP DocFeed() override;
-    STDMETHODIMP ClearDocFeedBuffer() override;
-    STDMETHODIMP StartReconvert() override;
-    STDMETHODIMP StartUndoCompositionString() override;
-};
diff --git a/dll/ime/msctfime/misc.cpp b/dll/ime/msctfime/misc.cpp
index 7cf38ad15b2..5b899c2ccfc 100644
--- a/dll/ime/msctfime/misc.cpp
+++ b/dll/ime/msctfime/misc.cpp
@@ -9,6 +9,185 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
 
+/// East-Asian language?
+/// @implemented
+BOOL IsEALang(LANGID LangID)
+{
+    if (LangID == 0)
+    {
+        TLS *pTLS = TLS::GetTLS();
+        if (!pTLS || !pTLS->m_pProfile)
+            return FALSE;
+
+        pTLS->m_pProfile->GetLangId(&LangID);
+    }
+
+    switch (PRIMARYLANGID(LangID))
+    {
+        case LANG_CHINESE:
+        case LANG_JAPANESE:
+        case LANG_KOREAN:
+            return TRUE;
+
+        default:
+            return FALSE;
+    }
+}
+
+typedef BOOLEAN (WINAPI *FN_DllShutdownInProgress)(VOID);
+
+/// This function calls ntdll!RtlDllShutdownInProgress.
+/// It can detect the system is shutting down or not.
+/// @implemented
+BOOLEAN DllShutdownInProgress(VOID)
+{
+    HMODULE hNTDLL;
+    static FN_DllShutdownInProgress s_fnDllShutdownInProgress = NULL;
+
+    if (s_fnDllShutdownInProgress)
+        return s_fnDllShutdownInProgress();
+
+    hNTDLL = cicGetSystemModuleHandle(L"ntdll.dll", FALSE);
+    s_fnDllShutdownInProgress =
+        (FN_DllShutdownInProgress)GetProcAddress(hNTDLL, 
"RtlDllShutdownInProgress");
+    if (!s_fnDllShutdownInProgress)
+        return FALSE;
+
+    return s_fnDllShutdownInProgress();
+}
+
+/// This function checks if the current user logon session is interactive.
+/// @implemented
+BOOL IsInteractiveUserLogon(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;
+}
+
+/// Gets the charset from a language ID.
+/// @implemented
+BYTE GetCharsetFromLangId(_In_ DWORD dwValue)
+{
+    CHARSETINFO info;
+    if (!::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwValue, &info, 
TCI_SRCLOCALE))
+        return 0;
+    return info.ciCharset;
+}
+
+/// Get the active input context.
+/// @implemented
+HIMC GetActiveContext(VOID)
+{
+    HWND hwndFocus = ::GetFocus();
+    if (!hwndFocus)
+        hwndFocus = ::GetActiveWindow();
+    return ::ImmGetContext(hwndFocus);
+}
+
+/// @implemented
+ITfCategoryMgr *GetUIMCat(PCIC_LIBTHREAD pLibThread)
+{
+    if (!pLibThread)
+        return NULL;
+
+    if (pLibThread->m_pCategoryMgr)
+        return pLibThread->m_pCategoryMgr;
+
+    if (FAILED(cicCoCreateInstance(CLSID_TF_CategoryMgr, NULL, 
CLSCTX_INPROC_SERVER,
+                                   IID_ITfCategoryMgr, (void 
**)&pLibThread->m_pCategoryMgr)))
+    {
+        return NULL;
+    }
+    return pLibThread->m_pCategoryMgr;
+}
+
+/// @implemented
+static HRESULT
+LibEnumItemsInCategory(PCIC_LIBTHREAD pLibThread, REFGUID rguid, IEnumGUID 
**ppEnum)
+{
+    ITfCategoryMgr *pCat = GetUIMCat(pLibThread);
+    if (!pCat)
+        return E_FAIL;
+    return pCat->EnumItemsInCategory(rguid, ppEnum);
+}
+
+/// @implemented
+HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
+{
+    if (!pLibThread)
+        return E_FAIL;
+
+    if (pLibThread->m_pDisplayAttrMgr)
+    {
+        pLibThread->m_pDisplayAttrMgr->Release();
+        pLibThread->m_pDisplayAttrMgr = NULL;
+    }
+
+    if (FAILED(cicCoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, 
CLSCTX_INPROC_SERVER,
+                                   IID_ITfDisplayAttributeMgr,
+                                   (void **)&pLibThread->m_pDisplayAttrMgr)))
+    {
+        return E_FAIL;
+    }
+
+    IEnumGUID *pEnumGuid;
+    LibEnumItemsInCategory(pLibThread, GUID_TFCAT_DISPLAYATTRIBUTEPROPERTY, 
&pEnumGuid);
+
+    HRESULT hr = E_OUTOFMEMORY;
+
+    ::EnterCriticalSection(&g_csLock);
+    if (pEnumGuid && !g_pPropCache)
+    {
+        g_pPropCache = new(cicNoThrow) CDispAttrPropCache();
+        if (g_pPropCache)
+        {
+            g_pPropCache->Add(GUID_PROP_ATTRIBUTE);
+            GUID guid;
+            while (pEnumGuid->Next(1, &guid, NULL) == S_OK)
+            {
+                if (!IsEqualGUID(guid, GUID_PROP_ATTRIBUTE))
+                    g_pPropCache->Add(guid);
+            }
+            hr = S_OK;
+        }
+    }
+    ::LeaveCriticalSection(&g_csLock);
+
+    return hr;
+}
+
+/// @implemented
+HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
+{
+    if (!pLibThread)
+        return E_FAIL;
+
+    if (pLibThread->m_pDisplayAttrMgr)
+    {
+        pLibThread->m_pDisplayAttrMgr->Release();
+        pLibThread->m_pDisplayAttrMgr = NULL;
+    }
+
+    return S_OK;
+}
+
+/***********************************************************************/
+
 /// @implemented
 HRESULT
 GetCompartment(
@@ -179,11 +358,13 @@ static const MODEBIAS g_ModeBiasMap[] =
     { GUID_MODEBIAS_NONE,       0x00000000 },
 };
 
+/// @implemented
 void CModeBias::SetModeBias(REFGUID rguid)
 {
     m_guid = rguid;
 }
 
+/// @implemented
 GUID CModeBias::ConvertModeBias(LONG bias)
 {
     const GUID *pguid = &GUID_NULL;
@@ -199,6 +380,7 @@ GUID CModeBias::ConvertModeBias(LONG bias)
     return *pguid;
 }
 
+/// @implemented
 LONG CModeBias::ConvertModeBias(REFGUID guid)
 {
     for (auto& item : g_ModeBiasMap)
@@ -211,25 +393,253 @@ LONG CModeBias::ConvertModeBias(REFGUID guid)
 
 /***********************************************************************/
 
-/// East-Asian language?
 /// @implemented
-BOOL IsEALang(VOID)
+CFunctionProviderBase::CFunctionProviderBase(_In_ TfClientId clientId)
 {
-    TLS *pTLS = TLS::GetTLS();
-    if (!pTLS || !pTLS->m_pProfile)
-        return FALSE;
+    m_clientId = clientId;
+    m_guid = GUID_NULL;
+    m_bstr = NULL;
+    m_cRefs = 1;
+}
 
-    LANGID LangID;
-    pTLS->m_pProfile->GetLangId(&LangID);
+/// @implemented
+CFunctionProviderBase::~CFunctionProviderBase()
+{
+    if (!DllShutdownInProgress())
+        ::SysFreeString(m_bstr);
+}
 
-    switch (PRIMARYLANGID(LangID))
+/// @implemented
+BOOL
+CFunctionProviderBase::Init(
+    _In_ REFGUID rguid,
+    _In_ LPCWSTR psz)
+{
+    m_bstr = ::SysAllocString(psz);
+    m_guid = rguid;
+    return (m_bstr != NULL);
+}
+
+/// @implemented
+STDMETHODIMP
+CFunctionProviderBase::QueryInterface(
+    _In_ REFIID riid,
+    _Out_ LPVOID* ppvObj)
+{
+    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, 
IID_ITfFunctionProvider))
     {
-        case LANG_CHINESE:
-        case LANG_JAPANESE:
-        case LANG_KOREAN:
-            return TRUE;
+        *ppvObj = this;
+        AddRef();
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
 
-        default:
-            return FALSE;
+/// @implemented
+STDMETHODIMP_(ULONG) CFunctionProviderBase::AddRef()
+{
+    return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFunctionProviderBase::Release()
+{
+    if (::InterlockedDecrement(&m_cRefs) == 0)
+    {
+        delete this;
+        return 0;
+    }
+    return m_cRefs;
+}
+
+/// @implemented
+STDMETHODIMP CFunctionProviderBase::GetType(_Out_ GUID *guid)
+{
+    *guid = m_guid;
+    return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP CFunctionProviderBase::GetDescription(_Out_ BSTR *desc)
+{
+    *desc = ::SysAllocString(m_bstr);
+    return (*desc ? S_OK : E_OUTOFMEMORY);
+}
+
+/***********************************************************************/
+
+/// @implemented
+CFunctionProvider::CFunctionProvider(_In_ TfClientId clientId) : 
CFunctionProviderBase(clientId)
+{
+    Init(CLSID_CAImmLayer, L"MSCTFIME::Function Provider");
+}
+
+/// @implemented
+STDMETHODIMP
+CFunctionProvider::GetFunction(
+    _In_ REFGUID guid,
+    _In_ REFIID riid,
+    _Out_ IUnknown **func)
+{
+    *func = NULL;
+
+    if (IsEqualGUID(guid, GUID_NULL) &&
+        IsEqualIID(riid, IID_IAImmFnDocFeed))
+    {
+        *func = new(cicNoThrow) CFnDocFeed();
+        if (*func)
+            return S_OK;
     }
+
+    return E_NOINTERFACE;
+}
+
+/***********************************************************************/
+
+CFnDocFeed::CFnDocFeed()
+{
+    m_cRefs = 1;
+}
+
+CFnDocFeed::~CFnDocFeed()
+{
+}
+
+/// @implemented
+STDMETHODIMP CFnDocFeed::QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj)
+{
+    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAImmFnDocFeed))
+    {
+        *ppvObj = this;
+        AddRef();
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFnDocFeed::AddRef()
+{
+    return ::InterlockedIncrement(&m_cRefs);
+}
+
+/// @implemented
+STDMETHODIMP_(ULONG) CFnDocFeed::Release()
+{
+    if (::InterlockedDecrement(&m_cRefs) == 0)
+    {
+        delete this;
+        return 0;
+    }
+    return m_cRefs;
+}
+
+/// @implemented
+STDMETHODIMP CFnDocFeed::DocFeed()
+{
+    TLS *pTLS = TLS::GetTLS();
+    if (!pTLS)
+        return E_OUTOFMEMORY;
+
+    HIMC hIMC = GetActiveContext();
+    CicIMCLock imcLock(hIMC);
+    if (FAILED(imcLock.m_hr))
+        return imcLock.m_hr;
+
+    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+    if (FAILED(imeContext.m_hr))
+        return imeContext.m_hr;
+    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+    if (!pCicIC)
+        return E_FAIL;
+
+    UINT uCodePage = CP_ACP;
+    pTLS->m_pProfile->GetCodePageA(&uCodePage);
+    pCicIC->SetupDocFeedString(imcLock, uCodePage);
+    return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP CFnDocFeed::ClearDocFeedBuffer()
+{
+    if (!TLS::GetTLS())
+        return E_OUTOFMEMORY;
+
+    HIMC hIMC = GetActiveContext();
+    CicIMCLock imcLock(hIMC);
+    if (FAILED(imcLock.m_hr))
+        return imcLock.m_hr;
+
+    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+    if (FAILED(imeContext.m_hr))
+        return imeContext.m_hr;
+
+    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+    if (!pCicIC)
+        return E_FAIL;
+
+    pCicIC->EscbClearDocFeedBuffer(imcLock, TRUE);
+    return S_OK;
+}
+
+/// @unimplemented
+STDMETHODIMP CFnDocFeed::StartReconvert()
+{
+    TLS *pTLS = TLS::GetTLS();
+    if (!pTLS)
+        return E_OUTOFMEMORY;
+    auto *pThreadMgr = pTLS->m_pThreadMgr;
+    if (!pThreadMgr)
+        return E_OUTOFMEMORY;
+
+    HIMC hIMC = GetActiveContext();
+    CicIMCLock imcLock(hIMC);
+    if (FAILED(imcLock.m_hr))
+        return imcLock.m_hr;
+
+    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+    if (FAILED(imeContext.m_hr))
+        return imeContext.m_hr;
+    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+    if (!pCicIC)
+        return E_FAIL;
+
+    UINT uCodePage = CP_ACP;
+    pTLS->m_pProfile->GetCodePageA(&uCodePage);
+
+    pCicIC->m_bReconverting = TRUE;
+    pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, 0, 0);
+    pCicIC->EndReconvertString(imcLock);
+    pCicIC->m_bReconverting = FALSE;
+    return S_OK;
+}
+
+/// @implemented
+STDMETHODIMP CFnDocFeed::StartUndoCompositionString()
+{
+    TLS *pTLS = TLS::GetTLS();
+    if (!pTLS)
+        return E_OUTOFMEMORY;
+    auto *pThreadMgr = pTLS->m_pThreadMgr;
+    if (!pThreadMgr)
+        return E_OUTOFMEMORY;
+
+    HIMC hIMC = GetActiveContext();
+    CicIMCLock imcLock(hIMC);
+    if (FAILED(imcLock.m_hr))
+        return imcLock.m_hr;
+
+    CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
+    if (FAILED(imeContext.m_hr))
+        return imeContext.m_hr;
+    CicInputContext *pCicIC = imeContext.get().m_pCicIC;
+    if (!pCicIC)
+        return E_FAIL;
+
+    UINT uCodePage = CP_ACP;
+    pTLS->m_pProfile->GetCodePageA(&uCodePage);
+
+    pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, 0, TRUE);
+    pCicIC->EndReconvertString(imcLock);
+    return S_OK;
 }
diff --git a/dll/ime/msctfime/misc.h b/dll/ime/msctfime/misc.h
index 49cca38c0cc..d5d17f15f53 100644
--- a/dll/ime/msctfime/misc.h
+++ b/dll/ime/msctfime/misc.h
@@ -7,6 +7,17 @@
 
 #pragma once
 
+BOOLEAN DllShutdownInProgress(VOID);
+BOOL IsEALang(LANGID LangID);
+BOOL IsInteractiveUserLogon(VOID);
+BYTE GetCharsetFromLangId(_In_ DWORD dwValue);
+HIMC GetActiveContext(VOID);
+ITfCategoryMgr *GetUIMCat(PCIC_LIBTHREAD pLibThread);
+HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread);
+HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread);
+
+/***********************************************************************/
+
 HRESULT
 GetCompartment(
     IUnknown *pUnknown,
@@ -59,4 +70,59 @@ public:
 
 /***********************************************************************/
 
-BOOL IsEALang(VOID);
+class CFunctionProviderBase : public ITfFunctionProvider
+{
+protected:
+    TfClientId m_clientId;
+    GUID m_guid;
+    BSTR m_bstr;
+    LONG m_cRefs;
+
+public:
+    CFunctionProviderBase(_In_ TfClientId clientId);
+    virtual ~CFunctionProviderBase();
+
+    // IUnknown interface
+    STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) 
override;
+    STDMETHODIMP_(ULONG) AddRef() override;
+    STDMETHODIMP_(ULONG) Release() override;
+
+    // ITfFunctionProvider interface
+    STDMETHODIMP GetType(_Out_ GUID *guid) override;
+    STDMETHODIMP GetDescription(_Out_ BSTR *desc) override;
+    //STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ 
IUnknown **func) = 0;
+
+    BOOL Init(_In_ REFGUID rguid, _In_ LPCWSTR psz);
+};
+
+/***********************************************************************/
+
+class CFunctionProvider : public CFunctionProviderBase
+{
+public:
+    CFunctionProvider(_In_ TfClientId clientId);
+
+    STDMETHODIMP GetFunction(_In_ REFGUID guid, _In_ REFIID riid, _Out_ 
IUnknown **func) override;
+};
+
+/***********************************************************************/
+
+class CFnDocFeed : public IAImmFnDocFeed
+{
+    LONG m_cRefs;
+
+public:
+    CFnDocFeed();
+    virtual ~CFnDocFeed();
+
+    // IUnknown interface
+    STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ LPVOID* ppvObj) 
override;
+    STDMETHODIMP_(ULONG) AddRef() override;
+    STDMETHODIMP_(ULONG) Release() override;
+
+    // IAImmFnDocFeed interface
+    STDMETHODIMP DocFeed() override;
+    STDMETHODIMP ClearDocFeedBuffer() override;
+    STDMETHODIMP StartReconvert() override;
+    STDMETHODIMP StartUndoCompositionString() override;
+};
diff --git a/dll/ime/msctfime/msctfime.cpp b/dll/ime/msctfime/msctfime.cpp
index 87ca208819c..cd4b4af212c 100644
--- a/dll/ime/msctfime/msctfime.cpp
+++ b/dll/ime/msctfime/msctfime.cpp
@@ -6,12 +6,9 @@
  */
 
 #include "msctfime.h"
-#include <ndk/ldrfuncs.h> /* for RtlDllShutdownInProgress */
 
 WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
 
-typedef CicArray<GUID> CDispAttrPropCache;
-
 HINSTANCE g_hInst = NULL; /* The instance of this module */
 BOOL g_bWinLogon = FALSE;
 UINT g_uACP = CP_ACP;
@@ -25,148 +22,6 @@ EXTERN_C void __cxa_pure_virtual(void)
     ERR("__cxa_pure_virtual\n");
 }
 
-typedef BOOLEAN (WINAPI *FN_DllShutdownInProgress)(VOID);
-
-/// This function calls ntdll!RtlDllShutdownInProgress.
-/// It can detect the system is shutting down or not.
-/// @implemented
-EXTERN_C BOOLEAN WINAPI DllShutdownInProgress(VOID)
-{
-    HMODULE hNTDLL;
-    static FN_DllShutdownInProgress s_fnDllShutdownInProgress = NULL;
-
-    if (s_fnDllShutdownInProgress)
-        return s_fnDllShutdownInProgress();
-
-    hNTDLL = cicGetSystemModuleHandle(L"ntdll.dll", FALSE);
-    s_fnDllShutdownInProgress =
-        (FN_DllShutdownInProgress)GetProcAddress(hNTDLL, 
"RtlDllShutdownInProgress");
-    if (!s_fnDllShutdownInProgress)
-        return FALSE;
-
-    return s_fnDllShutdownInProgress();
-}
-
-/// This function checks if the current user logon session is interactive.
-/// @implemented
-static BOOL
-IsInteractiveUserLogon(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;
-}
-
-/// @implemented
-ITfCategoryMgr *GetUIMCat(PCIC_LIBTHREAD pLibThread)
-{
-    if (!pLibThread)
-        return NULL;
-
-    if (pLibThread->m_pCategoryMgr)
-        return pLibThread->m_pCategoryMgr;
-
-    if (FAILED(cicCoCreateInstance(CLSID_TF_CategoryMgr, NULL, 
CLSCTX_INPROC_SERVER,
-                                   IID_ITfCategoryMgr, (void 
**)&pLibThread->m_pCategoryMgr)))
-    {
-        return NULL;
-    }
-    return pLibThread->m_pCategoryMgr;
-}
-
-/// @implemented
-HRESULT LibEnumItemsInCategory(PCIC_LIBTHREAD pLibThread, REFGUID rguid, 
IEnumGUID **ppEnum)
-{
-    ITfCategoryMgr *pCat = GetUIMCat(pLibThread);
-    if (!pCat)
-        return E_FAIL;
-    return pCat->EnumItemsInCategory(rguid, ppEnum);
-}
-
-/// @implemented
-HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
-{
-    if (!pLibThread)
-        return E_FAIL;
-
-    if (pLibThread->m_pDisplayAttrMgr)
-    {
-        pLibThread->m_pDisplayAttrMgr->Release();
-        pLibThread->m_pDisplayAttrMgr = NULL;
-    }
-
-    if (FAILED(cicCoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, 
CLSCTX_INPROC_SERVER,
-                                   IID_ITfDisplayAttributeMgr,
-                                   (void **)&pLibThread->m_pDisplayAttrMgr)))
-    {
-        return E_FAIL;
-    }
-
-    IEnumGUID *pEnumGuid;
-    LibEnumItemsInCategory(pLibThread, GUID_TFCAT_DISPLAYATTRIBUTEPROPERTY, 
&pEnumGuid);
-
-    HRESULT hr = E_OUTOFMEMORY;
-
-    ::EnterCriticalSection(&g_csLock);
-    if (pEnumGuid && !g_pPropCache)
-    {
-        g_pPropCache = new(cicNoThrow) CDispAttrPropCache();
-        if (g_pPropCache)
-        {
-            g_pPropCache->Add(GUID_PROP_ATTRIBUTE);
-            GUID guid;
-            while (pEnumGuid->Next(1, &guid, NULL) == S_OK)
-            {
-                if (!IsEqualGUID(guid, GUID_PROP_ATTRIBUTE))
-                    g_pPropCache->Add(guid);
-            }
-            hr = S_OK;
-        }
-    }
-    ::LeaveCriticalSection(&g_csLock);
-
-    return hr;
-}
-
-/// @implemented
-HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
-{
-    if (!pLibThread)
-        return E_FAIL;
-
-    if (pLibThread->m_pDisplayAttrMgr)
-    {
-        pLibThread->m_pDisplayAttrMgr->Release();
-        pLibThread->m_pDisplayAttrMgr = NULL;
-    }
-
-    return S_OK;
-}
-
-/// Gets the charset from a language ID.
-/// @implemented
-BYTE GetCharsetFromLangId(_In_ DWORD dwValue)
-{
-    CHARSETINFO info;
-    if (!::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwValue, &info, 
TCI_SRCLOCALE))
-        return 0;
-    return info.ciCharset;
-}
-
 /// Selects or unselects the input context.
 /// @implemented
 HRESULT
@@ -236,8 +91,6 @@ InternalSelectEx(
     return imcLock.m_hr;
 }
 
-class TLS;
-
 /***********************************************************************
  *      ImeInquire (MSCTFIME.@)
  *
@@ -245,6 +98,7 @@ class TLS;
  *
  * @implemented
  * @see CtfImeInquireExW
+ * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeInquire.html
  */
 EXTERN_C
 BOOL WINAPI
@@ -264,6 +118,7 @@ ImeInquire(
  *
  * @implemented
  * @see ImmGetConversionListW
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeConversionList.html
  */
 EXTERN_C DWORD WINAPI
 ImeConversionList(
@@ -284,6 +139,7 @@ ImeConversionList(
  *
  * @implemented
  * @see ImeUnregisterWord
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeRegisterWord.html
  */
 EXTERN_C BOOL WINAPI
 ImeRegisterWord(
@@ -302,6 +158,7 @@ ImeRegisterWord(
  *
  * @implemented
  * @see ImeRegisterWord
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeUnregisterWord.html
  */
 EXTERN_C BOOL WINAPI
 ImeUnregisterWord(
@@ -320,6 +177,7 @@ ImeUnregisterWord(
  *
  * @implemented
  * @see ImeRegisterWord
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeGetRegisterWordStyle.html
  */
 EXTERN_C UINT WINAPI
 ImeGetRegisterWordStyle(
@@ -337,6 +195,7 @@ ImeGetRegisterWordStyle(
  *
  * @implemented
  * @see ImeRegisterWord
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeEnumRegisterWord.html
  */
 EXTERN_C UINT WINAPI
 ImeEnumRegisterWord(
@@ -351,6 +210,12 @@ ImeEnumRegisterWord(
     return 0;
 }
 
+/***********************************************************************
+ *      ImeConfigure (MSCTFIME.@)
+ *
+ * @implemented
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeConfigure.html
+ */
 EXTERN_C BOOL WINAPI
 ImeConfigure(
     _In_ HKL hKL,
@@ -380,6 +245,7 @@ ImeConfigure(
  *      ImeDestroy (MSCTFIME.@)
  *
  * @implemented
+ * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeDestroy.html
  */
 EXTERN_C BOOL WINAPI
 ImeDestroy(
@@ -410,6 +276,7 @@ ImeDestroy(
  *
  * @implemented
  * @see CtfImeEscapeEx
+ * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeEscape.html
  */
 EXTERN_C LRESULT WINAPI
 ImeEscape(
@@ -439,6 +306,7 @@ ImeProcessKey(
  *
  * @implemented
  * @see CtfImeSelectEx
+ * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeSelect.html
  */
 EXTERN_C BOOL WINAPI
 ImeSelect(
@@ -456,6 +324,7 @@ ImeSelect(
  *
  * @implemented
  * @see CtfImeSetActiveContextAlways
+ * @see 
https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeSetActiveContext.html
  */
 EXTERN_C BOOL WINAPI
 ImeSetActiveContext(
@@ -480,6 +349,12 @@ ImeToAsciiEx(
     return 0;
 }
 
+/***********************************************************************
+ *      NotifyIME (MSCTFIME.@)
+ *
+ * @implemented
+ * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/NotifyIME.html
+ */
 EXTERN_C BOOL WINAPI
 NotifyIME(
     _In_ HIMC hIMC,
@@ -487,8 +362,19 @@ NotifyIME(
     _In_ DWORD dwIndex,
     _In_ DWORD_PTR dwValue)
 {
-    FIXME("stub:(%p, 0x%lX, 0x%lX, %p)\n", hIMC, dwAction, dwIndex, dwValue);
-    return FALSE;
+    TRACE("(%p, 0x%lX, 0x%lX, %p)\n", hIMC, dwAction, dwIndex, dwValue);
+
+    TLS *pTLS = TLS::GetTLS();
+    if (!pTLS)
+        return FALSE;
+
+    auto pBridge = pTLS->m_pBridge;
+    auto pThreadMgr = pTLS->m_pThreadMgr;
+    if (!pBridge || !pThreadMgr)
+        return FALSE;
+
+    HRESULT hr = pBridge->Notify(pTLS, pThreadMgr, hIMC, dwAction, dwIndex, 
dwValue);
+    return (hr == S_OK);
 }
 
 EXTERN_C BOOL WINAPI
@@ -704,11 +590,22 @@ CtfImeDestroyThreadMgr(VOID)
     return hr;
 }
 
+/***********************************************************************
+ *      CtfImeCreateInputContext (MSCTFIME.@)
+ *
+ * @implemented
+ */
 EXTERN_C HRESULT WINAPI
 CtfImeCreateInputContext(
     _In_ HIMC hIMC)
 {
-    return E_NOTIMPL;
+    TRACE("(%p)\n", hIMC);
+
+    TLS *pTLS = TLS::GetTLS();
+    if (!pTLS || !pTLS->m_pBridge)
+        return E_OUTOFMEMORY;
+
+    return pTLS->m_pBridge->CreateInputContext(pTLS, hIMC);
 }
 
 /***********************************************************************
@@ -729,6 +626,11 @@ CtfImeDestroyInputContext(
     return pTLS->m_pBridge->DestroyInputContext(pTLS, hIMC);
 }
 
+/***********************************************************************
+ *      CtfImeSetActiveContextAlways (MSCTFIME.@)
+ *
+ * @implemented
+ */
 EXTERN_C HRESULT WINAPI
 CtfImeSetActiveContextAlways(
     _In_ HIMC hIMC,
@@ -736,10 +638,13 @@ CtfImeSetActiveContextAlways(
     _In_ HWND hWnd,
     _In_ HKL hKL)
 {
-    FIXME("stub:(%p, %d, %p, %p)\n", hIMC, fActive, hWnd, hKL);
-    return E_NOTIMPL;
-}
+    TRACE("(%p, %d, %p, %p)\n", hIMC, fActive, hWnd, hKL);
 
+    TLS *pTLS = TLS::GetTLS();
+    if (!pTLS || !pTLS->m_pBridge)
+        return E_OUTOFMEMORY;
+    return pTLS->m_pBridge->SetActiveContextAlways(pTLS, hIMC, fActive, hWnd, 
hKL);
+}
 
 /***********************************************************************
  *      CtfImeProcessCicHotkey (MSCTFIME.@)
diff --git a/dll/ime/msctfime/msctfime.h b/dll/ime/msctfime/msctfime.h
index 59a89d537f2..48b184940df 100644
--- a/dll/ime/msctfime/msctfime.h
+++ b/dll/ime/msctfime/msctfime.h
@@ -35,18 +35,10 @@
 
 #include <wine/debug.h>
 
-EXTERN_C BOOLEAN WINAPI DllShutdownInProgress(VOID);
+extern CRITICAL_SECTION g_csLock;
 
-HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread);
-HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread);
-
-static inline HIMC GetActiveContext(VOID)
-{
-    HWND hwndFocus = ::GetFocus();
-    if (!hwndFocus)
-        hwndFocus = ::GetActiveWindow();
-    return ::ImmGetContext(hwndFocus);
-}
+typedef CicArray<GUID> CDispAttrPropCache;
+extern CDispAttrPropCache *g_pPropCache;
 
 DEFINE_GUID(GUID_COMPARTMENT_CTFIME_DIMFLAGS,        0xA94C5FD2, 0xC471, 
0x4031, 0x95, 0x46, 0x70, 0x9C, 0x17, 0x30, 0x0C, 0xB9);
 DEFINE_GUID(GUID_COMPARTMENT_CTFIME_CICINPUTCONTEXT, 0x85A688F7, 0x6DC8, 
0x4F17, 0xA8, 0x3A, 0xB1, 0x1C, 0x09, 0xCD, 0xD7, 0xBF);
@@ -55,13 +47,11 @@ DEFINE_GUID(GUID_MODEBIAS_NUMERIC,                   
0x4021766C, 0xE872, 0x48FD,
 DEFINE_GUID(GUID_MODEBIAS_URLHISTORY,                0x8B0E54D9, 0x63F2, 
0x4C68, 0x84, 0xD4, 0x79, 0xAE, 0xE7, 0xA5, 0x9F, 0x09);
 DEFINE_GUID(GUID_MODEBIAS_DEFAULT,                   0xF3DA8BD4, 0x0786, 
0x49C2, 0x8C, 0x09, 0x68, 0x39, 0xD8, 0xB8, 0x4F, 0x58);
 DEFINE_GUID(GUID_PROP_MODEBIAS,                      0x372E0716, 0x974F, 
0x40AC, 0xA0, 0x88, 0x08, 0xCD, 0xC9, 0x2E, 0xBF, 0xBC);
-
 #define GUID_MODEBIAS_NONE GUID_NULL
 
 #include "resource.h"
 
 #include "bridge.h"
-#include "functions.h"
 #include "inputcontext.h"
 #include "misc.h"
 #include "profile.h"
diff --git a/dll/ime/msctfime/tls.cpp b/dll/ime/msctfime/tls.cpp
index c6db21cc61e..392106e96ed 100644
--- a/dll/ime/msctfime/tls.cpp
+++ b/dll/ime/msctfime/tls.cpp
@@ -11,6 +11,38 @@ WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
 
 DWORD TLS::s_dwTlsIndex = (DWORD)-1;
 
+/// @implemented
+BOOL TLS::Initialize()
+{
+    s_dwTlsIndex = ::TlsAlloc();
+    return s_dwTlsIndex != (DWORD)-1;
+}
+
+/// @implemented
+VOID TLS::Uninitialize()
+{
+    if (s_dwTlsIndex != (DWORD)-1)
+    {
+        ::TlsFree(s_dwTlsIndex);
+        s_dwTlsIndex = (DWORD)-1;
+    }
+}
+
+/// @implemented
+TLS* TLS::GetTLS()
+{
+    if (s_dwTlsIndex == (DWORD)-1)
+        return NULL;
+
+    return InternalAllocateTLS();
+}
+
+/// @implemented
+TLS* TLS::PeekTLS()
+{
+    return (TLS*)::TlsGetValue(TLS::s_dwTlsIndex);
+}
+
 /// @implemented
 TLS* TLS::InternalAllocateTLS()
 {
diff --git a/dll/ime/msctfime/tls.h b/dll/ime/msctfime/tls.h
index 2d2c882a67e..87788650d46 100644
--- a/dll/ime/msctfime/tls.h
+++ b/dll/ime/msctfime/tls.h
@@ -7,8 +7,6 @@
 
 #pragma once
 
-class TLS;
-
 class CicBridge;
 class CicProfile;
 
@@ -29,45 +27,11 @@ public:
     DWORD m_NonEAComposition;
     DWORD m_cWnds;
 
-    /**
-     * @implemented
-     */
-    static BOOL Initialize()
-    {
-        s_dwTlsIndex = ::TlsAlloc();
-        return s_dwTlsIndex != (DWORD)-1;
-    }
-
-    /**
-     * @implemented
-     */
-    static VOID Uninitialize()
-    {
-        if (s_dwTlsIndex != (DWORD)-1)
-        {
-            ::TlsFree(s_dwTlsIndex);
-            s_dwTlsIndex = (DWORD)-1;
-        }
-    }
-
-    /**
-     * @implemented
-     */
-    static TLS* GetTLS()
-    {
-        if (s_dwTlsIndex == (DWORD)-1)
-            return NULL;
-
-        return InternalAllocateTLS();
-    }
+    static BOOL Initialize();
+    static VOID Uninitialize();
 
-    /**
-     * @implemented
-     */
-    static TLS* PeekTLS()
-    {
-        return (TLS*)::TlsGetValue(TLS::s_dwTlsIndex);
-    }
+    static TLS* GetTLS();
+    static TLS* PeekTLS();
 
     static TLS* InternalAllocateTLS();
     static BOOL InternalDestroyTLS();
diff --git a/dll/ime/msctfime/ui.cpp b/dll/ime/msctfime/ui.cpp
index 7b6b5b2a2fc..650c88171fc 100644
--- a/dll/ime/msctfime/ui.cpp
+++ b/dll/ime/msctfime/ui.cpp
@@ -529,7 +529,7 @@ HRESULT UIComposition::CreateCompButtonWnd(HWND hwndParent, 
HIMC hIMC)
     if (!pTLS || !pTLS->NonEACompositionEnabled())
         return S_OK;
 
-    if (IsEALang())
+    if (IsEALang(0))
     {
         if (m_pCompButtonFrameWindow)
         {
diff --git a/dll/ime/msctfime/ui.h b/dll/ime/msctfime/ui.h
index 72dd14c7761..3d9c822755a 100644
--- a/dll/ime/msctfime/ui.h
+++ b/dll/ime/msctfime/ui.h
@@ -44,8 +44,6 @@ public:
 
 /***********************************************************************/
 
-class CCompFrameWindow;
-
 class CCompFinalizeButton : public CUIFToolbarButton
 {
 public:

Reply via email to