https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0b7405abf20e33caaf944…
commit 0b7405abf20e33caaf944560483f7247e80d3558
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Dec 20 12:29:03 2023 +0900
Commit: GitHub <noreply(a)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
*/