https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0b7405abf20e33caaf944560483f7247e80d3558

commit 0b7405abf20e33caaf944560483f7247e80d3558
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Wed Dec 20 12:29:03 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Wed Dec 20 12:29:03 2023 +0900

    [MSCTFIME] Implement CActiveLanguageProfileNotifySink (#6200)
    
    - Add link to msctf.dll.
    - Implement CActiveLanguageProfileNotifySink class.
    - Strengthen CicProfile class.
    CORE-19360
---
 dll/ime/msctfime/CMakeLists.txt |   2 +-
 dll/ime/msctfime/msctfime.cpp   | 368 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 368 insertions(+), 2 deletions(-)

diff --git a/dll/ime/msctfime/CMakeLists.txt b/dll/ime/msctfime/CMakeLists.txt
index db81c3f65e6..72e89de4e9c 100644
--- a/dll/ime/msctfime/CMakeLists.txt
+++ b/dll/ime/msctfime/CMakeLists.txt
@@ -17,5 +17,5 @@ add_library(msctfime MODULE
 set_module_type(msctfime win32dll UNICODE)
 set_target_properties(msctfime PROPERTIES SUFFIX ".ime")
 target_link_libraries(msctfime wine uuid)
-add_importlibs(msctfime oleaut32 imm32 user32 gdi32 advapi32 comctl32 msvcrt 
kernel32 ntdll)
+add_importlibs(msctfime msctf oleaut32 imm32 user32 gdi32 advapi32 comctl32 
msvcrt kernel32 ntdll)
 add_cd_file(TARGET msctfime DESTINATION reactos/system32 FOR all)
diff --git a/dll/ime/msctfime/msctfime.cpp b/dll/ime/msctfime/msctfime.cpp
index 8ada6608e6c..b2a0b979bbb 100644
--- a/dll/ime/msctfime/msctfime.cpp
+++ b/dll/ime/msctfime/msctfime.cpp
@@ -334,12 +334,348 @@ public:
     HRESULT ConfigureRegisterWord(TLS* pTLS, ITfThreadMgr *pThreadMgr, HKL 
hKL, HWND hWnd, LPVOID lpData);
 };
 
+class CActiveLanguageProfileNotifySink : public 
ITfActiveLanguageProfileNotifySink
+{
+protected:
+    typedef INT (CALLBACK *FN_COMPARE)(REFGUID rguid1, REFGUID rguid2, BOOL 
fActivated, LPVOID pUserData);
+    LONG m_cRefs;
+    ITfThreadMgr *m_pThreadMgr;
+    DWORD m_dwConnection;
+    FN_COMPARE m_fnCompare;
+    LPVOID m_pUserData;
+
+public:
+    CActiveLanguageProfileNotifySink(FN_COMPARE fnCompare, void *pUserData);
+    virtual ~CActiveLanguageProfileNotifySink();
+
+    HRESULT _Advise(ITfThreadMgr *pThreadMgr);
+    HRESULT _Unadvise();
+
+    // IUnknown interface
+    STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
+    STDMETHODIMP_(ULONG) AddRef() override;
+    STDMETHODIMP_(ULONG) Release() override;
+
+    // ITfActiveLanguageProfileNotifySink interface
+    STDMETHODIMP
+    OnActivated(
+        REFCLSID clsid,
+        REFGUID guidProfile,
+        BOOL fActivated) override;
+};
+
+/**
+ * @implemented
+ */
+CActiveLanguageProfileNotifySink::CActiveLanguageProfileNotifySink(
+    FN_COMPARE fnCompare,
+    void *pUserData)
+{
+    m_dwConnection = (DWORD)-1;
+    m_fnCompare = fnCompare;
+    m_cRefs = 1;
+    m_pUserData = pUserData;
+}
+
+/**
+ * @implemented
+ */
+CActiveLanguageProfileNotifySink::~CActiveLanguageProfileNotifySink()
+{
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP CActiveLanguageProfileNotifySink::QueryInterface(REFIID riid, 
LPVOID* ppvObj)
+{
+    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, 
IID_ITfActiveLanguageProfileNotifySink))
+    {
+        *ppvObj = this;
+        AddRef();
+        return S_OK;
+    }
+    *ppvObj = NULL;
+    return E_NOINTERFACE;
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::AddRef()
+{
+    return ::InterlockedIncrement(&m_cRefs);
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::Release()
+{
+    if (::InterlockedDecrement(&m_cRefs) == 0)
+    {
+        delete this;
+        return 0;
+    }
+    return m_cRefs;
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP
+CActiveLanguageProfileNotifySink::OnActivated(
+    REFCLSID clsid,
+    REFGUID guidProfile,
+    BOOL fActivated)
+{
+    if (!m_fnCompare)
+        return 0;
+
+    return m_fnCompare(clsid, guidProfile, fActivated, m_pUserData);
+}
+
+/**
+ * @implemented
+ */
+HRESULT
+CActiveLanguageProfileNotifySink::_Advise(
+    ITfThreadMgr *pThreadMgr)
+{
+    m_pThreadMgr = NULL;
+
+    ITfSource *pSource = NULL;
+    HRESULT hr = pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
+    if (FAILED(hr))
+        return E_FAIL;
+
+    hr = pSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, this, 
&m_dwConnection);
+    if (SUCCEEDED(hr))
+    {
+        m_pThreadMgr = pThreadMgr;
+        pThreadMgr->AddRef();
+        hr = S_OK;
+    }
+    else
+    {
+        hr = E_FAIL;
+    }
+
+    if (pSource)
+        pSource->Release();
+
+    return hr;
+}
+
+/**
+ * @implemented
+ */
+HRESULT
+CActiveLanguageProfileNotifySink::_Unadvise()
+{
+    if (!m_pThreadMgr)
+        return E_FAIL;
+
+    ITfSource *pSource = NULL;
+    HRESULT hr = m_pThreadMgr->QueryInterface(IID_ITfSource, (void 
**)&pSource);
+    if (SUCCEEDED(hr))
+    {
+        hr = pSource->UnadviseSink(m_dwConnection);
+        if (SUCCEEDED(hr))
+            hr = S_OK;
+    }
+
+    if (pSource)
+        pSource->Release();
+
+    if (m_pThreadMgr)
+    {
+        m_pThreadMgr->Release();
+        m_pThreadMgr = NULL;
+    }
+
+    return hr;
+}
+
 /* FIXME */
-struct CicProfile : IUnknown
+class CicProfile : public IUnknown
 {
+protected:
+    ITfInputProcessorProfiles *m_pIPProfiles;
+    CActiveLanguageProfileNotifySink *m_pActiveLanguageProfileNotifySink;
+    LANGID  m_LangID1;
+    WORD    m_padding1;
+    DWORD   m_dwFlags;
+    UINT    m_nCodePage;
+    LANGID  m_LangID2;
+    WORD    m_padding2;
+    DWORD   m_dw3[1];
+    LONG    m_cRefs;
+
+    static INT CALLBACK
+    ActiveLanguageProfileNotifySinkCallback(
+        REFGUID rguid1,
+        REFGUID rguid2,
+        BOOL fActivated,
+        LPVOID pUserData);
+
+public:
+    CicProfile();
+    virtual ~CicProfile();
+
+    // IUnknown interface
+    STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override;
+    STDMETHODIMP_(ULONG) AddRef() override;
+    STDMETHODIMP_(ULONG) Release() override;
+
     HRESULT GetActiveLanguageProfile(HKL hKL, REFGUID rguid, 
TF_LANGUAGEPROFILE *pProfile);
+    HRESULT GetLangId(LANGID *pLangID);
+    HRESULT GetCodePageA(UINT *puCodePage);
+
+    HRESULT InitProfileInstance(TLS *pTLS);
 };
 
+/**
+ * @implemented
+ */
+CicProfile::CicProfile()
+{
+    m_dwFlags &= 0xFFFFFFF0;
+    m_cRefs = 1;
+    m_pIPProfiles = NULL;
+    m_pActiveLanguageProfileNotifySink = NULL;
+    m_LangID1 = 0;
+    m_nCodePage = CP_ACP;
+    m_LangID2 = 0;
+    m_dw3[0] = 0;
+}
+
+/**
+ * @implemented
+ */
+CicProfile::~CicProfile()
+{
+    if (m_pIPProfiles)
+    {
+        if (m_LangID1)
+            m_pIPProfiles->ChangeCurrentLanguage(m_LangID1);
+
+        m_pIPProfiles->Release();
+        m_pIPProfiles = NULL;
+    }
+
+    if (m_pActiveLanguageProfileNotifySink)
+    {
+        m_pActiveLanguageProfileNotifySink->_Unadvise();
+        m_pActiveLanguageProfileNotifySink->Release();
+        m_pActiveLanguageProfileNotifySink = NULL;
+    }
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP CicProfile::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+    *ppvObj = NULL;
+    return E_NOINTERFACE;
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP_(ULONG) CicProfile::AddRef()
+{
+    return ::InterlockedIncrement(&m_cRefs);
+}
+
+/**
+ * @implemented
+ */
+STDMETHODIMP_(ULONG) CicProfile::Release()
+{
+    if (::InterlockedDecrement(&m_cRefs) == 0)
+    {
+        delete this;
+        return 0;
+    }
+    return m_cRefs;
+}
+
+/**
+ * @implemented
+ */
+INT CALLBACK
+CicProfile::ActiveLanguageProfileNotifySinkCallback(
+    REFGUID rguid1,
+    REFGUID rguid2,
+    BOOL fActivated,
+    LPVOID pUserData)
+{
+    CicProfile *pThis = (CicProfile *)pUserData;
+    pThis->m_dwFlags &= ~0xE;
+    return 0;
+}
+
+/**
+ * @implemented
+ */
+HRESULT CicProfile::GetCodePageA(UINT *puCodePage)
+{
+    if (!puCodePage)
+        return E_INVALIDARG;
+
+    if (m_dwFlags & 2)
+    {
+        *puCodePage = m_nCodePage;
+        return S_OK;
+    }
+
+    *puCodePage = 0;
+
+    LANGID LangID;
+    HRESULT hr = GetLangId(&LangID);
+    if (FAILED(hr))
+        return E_FAIL;
+
+    WCHAR szBuff[12];
+    INT cch = ::GetLocaleInfoW(LangID, LOCALE_IDEFAULTANSICODEPAGE, szBuff, 
_countof(szBuff));
+    if (cch)
+    {
+        szBuff[cch] = 0;
+        m_nCodePage = *puCodePage = wcstoul(szBuff, NULL, 10);
+        m_dwFlags |= 2;
+    }
+
+    return S_OK;
+}
+
+/**
+ * @implemented
+ */
+HRESULT CicProfile::GetLangId(LANGID *pLangID)
+{
+    *pLangID = 0;
+
+    if (!m_pIPProfiles)
+        return E_FAIL;
+
+    if (m_dwFlags & 4)
+    {
+        *pLangID = m_LangID2;
+        return S_OK;
+    }
+
+    HRESULT hr = m_pIPProfiles->GetCurrentLanguage(pLangID);
+    if (SUCCEEDED(hr))
+    {
+        m_dwFlags |= 4;
+        m_LangID2 = *pLangID;
+    }
+
+    return hr;
+}
+
 class TLS
 {
 public:
@@ -449,6 +785,36 @@ BOOL TLS::InternalDestroyTLS()
     return TRUE;
 }
 
+/**
+ * @implemented
+ */
+HRESULT
+CicProfile::InitProfileInstance(TLS *pTLS)
+{
+    HRESULT hr = TF_CreateInputProcessorProfiles(&m_pIPProfiles);
+    if (FAILED(hr))
+        return hr;
+
+    if (!m_pActiveLanguageProfileNotifySink)
+    {
+        CActiveLanguageProfileNotifySink *pSink =
+            new CActiveLanguageProfileNotifySink(
+                CicProfile::ActiveLanguageProfileNotifySinkCallback, this);
+        if (!pSink)
+        {
+            m_pIPProfiles->Release();
+            m_pIPProfiles = NULL;
+            return E_FAIL;
+        }
+        m_pActiveLanguageProfileNotifySink = pSink;
+    }
+
+    if (pTLS->m_pThreadMgr)
+        m_pActiveLanguageProfileNotifySink->_Advise(pTLS->m_pThreadMgr);
+
+    return hr;
+}
+
 /***********************************************************************
  *      CicBridge
  */

Reply via email to