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 */