diff --git a/base/ctf/msctf/CMakeLists.txt b/base/ctf/msctf/CMakeLists.txt index fec41c946ca..9619476ff78 100644 --- a/base/ctf/msctf/CMakeLists.txt +++ b/base/ctf/msctf/CMakeLists.txt @@ -8,7 +8,6 @@ list(APPEND SOURCE categorymgr.c compartmentmgr.c context.c - documentmgr.c inputprocessor.c msctf.c threadmgr.c @@ -17,6 +16,7 @@ list(APPEND SOURCE list(APPEND PCH_SKIP_SOURCE displayattributemgr.cpp + documentmgr.cpp langbarmgr.cpp mlng.cpp range.cpp diff --git a/base/ctf/msctf/documentmgr.c b/base/ctf/msctf/documentmgr.c deleted file mode 100644 index 44856db632b..00000000000 --- a/base/ctf/msctf/documentmgr.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * ITfDocumentMgr implementation - * - * Copyright 2009 Aric Stewart, CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include - -#define COBJMACROS - -#include "wine/debug.h" -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winuser.h" -#include "shlwapi.h" -#include "winerror.h" -#include "objbase.h" - -#include "msctf.h" -#include "msctf_internal.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msctf); - -typedef struct tagDocumentMgr { - ITfDocumentMgr ITfDocumentMgr_iface; - ITfSource ITfSource_iface; - LONG refCount; - - /* Aggregation */ - ITfCompartmentMgr *CompartmentMgr; - - ITfContext* contextStack[2]; /* limit of 2 contexts */ - ITfThreadMgrEventSink* ThreadMgrSink; - - struct list TransitoryExtensionSink; -} DocumentMgr; - -typedef struct tagEnumTfContext { - IEnumTfContexts IEnumTfContexts_iface; - LONG refCount; - - DWORD index; - DocumentMgr *docmgr; -} EnumTfContext; - -static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut); - -static inline DocumentMgr *impl_from_ITfDocumentMgr(ITfDocumentMgr *iface) -{ - return CONTAINING_RECORD(iface, DocumentMgr, ITfDocumentMgr_iface); -} - -static inline DocumentMgr *impl_from_ITfSource(ITfSource *iface) -{ - return CONTAINING_RECORD(iface, DocumentMgr, ITfSource_iface); -} - -static inline EnumTfContext *impl_from_IEnumTfContexts(IEnumTfContexts *iface) -{ - return CONTAINING_RECORD(iface, EnumTfContext, IEnumTfContexts_iface); -} - -static void DocumentMgr_Destructor(DocumentMgr *This) -{ - ITfThreadMgr *tm = NULL; - TRACE("destroying %p\n", This); - - TF_GetThreadMgr(&tm); - if (tm) - { - ThreadMgr_OnDocumentMgrDestruction(tm, &This->ITfDocumentMgr_iface); - ITfThreadMgr_Release(tm); - } - - if (This->contextStack[0]) - ITfContext_Release(This->contextStack[0]); - if (This->contextStack[1]) - ITfContext_Release(This->contextStack[1]); - free_sinks(&This->TransitoryExtensionSink); - CompartmentMgr_Destructor(This->CompartmentMgr); - HeapFree(GetProcessHeap(),0,This); -} - -static HRESULT WINAPI DocumentMgr_QueryInterface(ITfDocumentMgr *iface, REFIID iid, LPVOID *ppvOut) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - *ppvOut = NULL; - - if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfDocumentMgr)) - { - *ppvOut = &This->ITfDocumentMgr_iface; - } - else if (IsEqualIID(iid, &IID_ITfSource)) - { - *ppvOut = &This->ITfSource_iface; - } - else if (IsEqualIID(iid, &IID_ITfCompartmentMgr)) - { - *ppvOut = This->CompartmentMgr; - } - - if (*ppvOut) - { - ITfDocumentMgr_AddRef(iface); - return S_OK; - } - - WARN("unsupported interface: %s\n", debugstr_guid(iid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI DocumentMgr_AddRef(ITfDocumentMgr *iface) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - return InterlockedIncrement(&This->refCount); -} - -static ULONG WINAPI DocumentMgr_Release(ITfDocumentMgr *iface) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - ULONG ret; - - ret = InterlockedDecrement(&This->refCount); - if (ret == 0) - DocumentMgr_Destructor(This); - return ret; -} - -/***************************************************** - * ITfDocumentMgr functions - *****************************************************/ -static HRESULT WINAPI DocumentMgr_CreateContext(ITfDocumentMgr *iface, - TfClientId tidOwner, - DWORD dwFlags, IUnknown *punk, ITfContext **ppic, - TfEditCookie *pecTextStore) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - TRACE("(%p) 0x%x 0x%x %p %p %p\n",This,tidOwner,dwFlags,punk,ppic,pecTextStore); - return Context_Constructor(tidOwner, punk, iface, ppic, pecTextStore); -} - -static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - ITfContext *check; - - TRACE("(%p) %p\n",This,pic); - - if (This->contextStack[1]) /* FUll */ - return TF_E_STACKFULL; - - if (!pic || FAILED(ITfContext_QueryInterface(pic,&IID_ITfContext,(LPVOID*) &check))) - return E_INVALIDARG; - - if (This->contextStack[0] == NULL) - ITfThreadMgrEventSink_OnInitDocumentMgr(This->ThreadMgrSink,iface); - - This->contextStack[1] = This->contextStack[0]; - This->contextStack[0] = check; - - Context_Initialize(check, iface); - ITfThreadMgrEventSink_OnPushContext(This->ThreadMgrSink,check); - - return S_OK; -} - -static HRESULT WINAPI DocumentMgr_Pop(ITfDocumentMgr *iface, DWORD dwFlags) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - TRACE("(%p) 0x%x\n",This,dwFlags); - - if (dwFlags == TF_POPF_ALL) - { - int i; - - for (i = 0; i < ARRAY_SIZE(This->contextStack); i++) - if (This->contextStack[i]) - { - ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink, This->contextStack[i]); - Context_Uninitialize(This->contextStack[i]); - ITfContext_Release(This->contextStack[i]); - This->contextStack[i] = NULL; - } - - ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface); - return S_OK; - } - - if (dwFlags) - return E_INVALIDARG; - - if (This->contextStack[1] == NULL) /* Cannot pop last context */ - return E_FAIL; - - ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink,This->contextStack[0]); - Context_Uninitialize(This->contextStack[0]); - ITfContext_Release(This->contextStack[0]); - This->contextStack[0] = This->contextStack[1]; - This->contextStack[1] = NULL; - - if (This->contextStack[0] == NULL) - ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface); - - return S_OK; -} - -static HRESULT WINAPI DocumentMgr_GetTop(ITfDocumentMgr *iface, ITfContext **ppic) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - TRACE("(%p)\n",This); - if (!ppic) - return E_INVALIDARG; - - if (This->contextStack[0]) - ITfContext_AddRef(This->contextStack[0]); - - *ppic = This->contextStack[0]; - - return S_OK; -} - -static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **ppic) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - ITfContext *tgt; - - TRACE("(%p)\n",This); - if (!ppic) - return E_INVALIDARG; - - if (This->contextStack[1]) - tgt = This->contextStack[1]; - else - tgt = This->contextStack[0]; - - if (tgt) - ITfContext_AddRef(tgt); - - *ppic = tgt; - - return S_OK; -} - -static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum) -{ - DocumentMgr *This = impl_from_ITfDocumentMgr(iface); - TRACE("(%p) %p\n",This,ppEnum); - return EnumTfContext_Constructor(This, ppEnum); -} - -static const ITfDocumentMgrVtbl DocumentMgrVtbl = -{ - DocumentMgr_QueryInterface, - DocumentMgr_AddRef, - DocumentMgr_Release, - DocumentMgr_CreateContext, - DocumentMgr_Push, - DocumentMgr_Pop, - DocumentMgr_GetTop, - DocumentMgr_GetBase, - DocumentMgr_EnumContexts -}; - -static HRESULT WINAPI DocumentMgrSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) -{ - DocumentMgr *This = impl_from_ITfSource(iface); - return ITfDocumentMgr_QueryInterface(&This->ITfDocumentMgr_iface, iid, ppvOut); -} - -static ULONG WINAPI DocumentMgrSource_AddRef(ITfSource *iface) -{ - DocumentMgr *This = impl_from_ITfSource(iface); - return ITfDocumentMgr_AddRef(&This->ITfDocumentMgr_iface); -} - -static ULONG WINAPI DocumentMgrSource_Release(ITfSource *iface) -{ - DocumentMgr *This = impl_from_ITfSource(iface); - return ITfDocumentMgr_Release(&This->ITfDocumentMgr_iface); -} - -/***************************************************** - * ITfSource functions - *****************************************************/ -static HRESULT WINAPI DocumentMgrSource_AdviseSink(ITfSource *iface, - REFIID riid, IUnknown *punk, DWORD *pdwCookie) -{ - DocumentMgr *This = impl_from_ITfSource(iface); - - TRACE("(%p) %s %p %p\n", This, debugstr_guid(riid), punk, pdwCookie); - - if (!riid || !punk || !pdwCookie) - return E_INVALIDARG; - - if (IsEqualIID(riid, &IID_ITfTransitoryExtensionSink)) - { - WARN("semi-stub for ITfTransitoryExtensionSink: callback won't be used.\n"); - return advise_sink(&This->TransitoryExtensionSink, &IID_ITfTransitoryExtensionSink, - COOKIE_MAGIC_DMSINK, punk, pdwCookie); - } - - FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); - return E_NOTIMPL; -} - -static HRESULT WINAPI DocumentMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) -{ - DocumentMgr *This = impl_from_ITfSource(iface); - - TRACE("(%p) %x\n",This,pdwCookie); - - if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_DMSINK) - return E_INVALIDARG; - - return unadvise_sink(pdwCookie); -} - -static const ITfSourceVtbl DocumentMgrSourceVtbl = -{ - DocumentMgrSource_QueryInterface, - DocumentMgrSource_AddRef, - DocumentMgrSource_Release, - DocumentMgrSource_AdviseSink, - DocumentMgrSource_UnadviseSink, -}; - -HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumentMgr **ppOut) -{ - DocumentMgr *This; - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DocumentMgr)); - if (This == NULL) - return E_OUTOFMEMORY; - - This->ITfDocumentMgr_iface.lpVtbl = &DocumentMgrVtbl; - This->ITfSource_iface.lpVtbl = &DocumentMgrSourceVtbl; - This->refCount = 1; - This->ThreadMgrSink = ThreadMgrSink; - list_init(&This->TransitoryExtensionSink); - - CompartmentMgr_Constructor((IUnknown*)&This->ITfDocumentMgr_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); - - *ppOut = &This->ITfDocumentMgr_iface; - TRACE("returning %p\n", *ppOut); - return S_OK; -} - -/************************************************** - * IEnumTfContexts implementation - **************************************************/ -static void EnumTfContext_Destructor(EnumTfContext *This) -{ - TRACE("destroying %p\n", This); - HeapFree(GetProcessHeap(),0,This); -} - -static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - *ppvOut = NULL; - - if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts)) - { - *ppvOut = &This->IEnumTfContexts_iface; - } - - if (*ppvOut) - { - IEnumTfContexts_AddRef(iface); - return S_OK; - } - - WARN("unsupported interface: %s\n", debugstr_guid(iid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - return InterlockedIncrement(&This->refCount); -} - -static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - ULONG ret; - - ret = InterlockedDecrement(&This->refCount); - if (ret == 0) - EnumTfContext_Destructor(This); - return ret; -} - -static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface, - ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - ULONG fetched = 0; - - TRACE("(%p)\n",This); - - if (rgContext == NULL) return E_POINTER; - - while (fetched < ulCount) - { - if (This->index > 1) - break; - - if (!This->docmgr->contextStack[This->index]) - break; - - *rgContext = This->docmgr->contextStack[This->index]; - ITfContext_AddRef(*rgContext); - - ++This->index; - ++fetched; - ++rgContext; - } - - if (pcFetched) *pcFetched = fetched; - return fetched == ulCount ? S_OK : S_FALSE; -} - -static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - TRACE("(%p)\n",This); - This->index += celt; - return S_OK; -} - -static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - TRACE("(%p)\n",This); - This->index = 0; - return S_OK; -} - -static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface, - IEnumTfContexts **ppenum) -{ - EnumTfContext *This = impl_from_IEnumTfContexts(iface); - HRESULT res; - - TRACE("(%p)\n",This); - - if (ppenum == NULL) return E_POINTER; - - res = EnumTfContext_Constructor(This->docmgr, ppenum); - if (SUCCEEDED(res)) - { - EnumTfContext *new_This = impl_from_IEnumTfContexts(*ppenum); - new_This->index = This->index; - } - return res; -} - -static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={ - EnumTfContext_QueryInterface, - EnumTfContext_AddRef, - EnumTfContext_Release, - - EnumTfContext_Clone, - EnumTfContext_Next, - EnumTfContext_Reset, - EnumTfContext_Skip -}; - -static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut) -{ - EnumTfContext *This; - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext)); - if (This == NULL) - return E_OUTOFMEMORY; - - This->IEnumTfContexts_iface.lpVtbl = &IEnumTfContexts_Vtbl; - This->refCount = 1; - This->docmgr = mgr; - - *ppOut = &This->IEnumTfContexts_iface; - TRACE("returning %p\n", *ppOut); - return S_OK; -} diff --git a/base/ctf/msctf/documentmgr.cpp b/base/ctf/msctf/documentmgr.cpp new file mode 100644 index 00000000000..a3b93020638 --- /dev/null +++ b/base/ctf/msctf/documentmgr.cpp @@ -0,0 +1,461 @@ +/* + * PROJECT: ReactOS CTF + * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) + * PURPOSE: Implementation of ITfDocumentMgr and IEnumTfContexts + * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers + * Copyright 2025 Katayama Hirofumi MZ + */ + +#include +#include +#include +#include +#include +#include +#include + +// Cicero +#include + +#include "documentmgr.h" +#include "msctf_internal.h" + +#include +WINE_DEFAULT_DEBUG_CHANNEL(msctf); + +EXTERN_C +HRESULT EnumTfContext_Constructor(CDocumentMgr *mgr, IEnumTfContexts **ppOut); + +//////////////////////////////////////////////////////////////////////////// +// CDocumentMgr + +CDocumentMgr::CDocumentMgr(ITfThreadMgrEventSink *threadMgrSink) + : m_cRefs(1) + , m_pCompartmentMgr(NULL) + , m_pThreadMgrSink(threadMgrSink) +{ + m_contextStack[1] = m_contextStack[0] = NULL; + + list_init(&m_transitoryExtensionSink); + + ITfDocumentMgr *pDocMgr = static_cast(this); + ITfCompartmentMgr **ppCompMgr = static_cast(&m_pCompartmentMgr); + CompartmentMgr_Constructor(pDocMgr, IID_IUnknown, reinterpret_cast(ppCompMgr)); +} + +CDocumentMgr::~CDocumentMgr() +{ + TRACE("destroying %p\n", this); + + ITfThreadMgr *tm = NULL; + TF_GetThreadMgr(&tm); + if (tm) + { + ThreadMgr_OnDocumentMgrDestruction(tm, static_cast(this)); + tm->Release(); + } + + if (m_contextStack[0]) + { + m_contextStack[0]->Release(); + m_contextStack[0] = NULL; + } + + if (m_contextStack[1]) + { + m_contextStack[1]->Release(); + m_contextStack[1] = NULL; + } + + free_sinks(&m_transitoryExtensionSink); + + if (m_pCompartmentMgr) + { + m_pCompartmentMgr->Release(); + m_pCompartmentMgr = NULL; + } +} + +HRESULT +CDocumentMgr::CreateInstance( + _In_ ITfThreadMgrEventSink *pThreadMgrSink, + _Out_ ITfDocumentMgr **ppOut) +{ + if (!ppOut) + { + ERR("!ppOut\n"); + return E_POINTER; + } + + if (!pThreadMgrSink) + { + ERR("!pThreadMgrSink\n"); + return E_INVALIDARG; + } + + CDocumentMgr *This = new(cicNoThrow) CDocumentMgr(pThreadMgrSink); + if (!This) + { + ERR("E_OUTOFMEMORY\n"); + return E_OUTOFMEMORY; + } + + *ppOut = static_cast(This); + TRACE("returning %p\n", *ppOut); + return S_OK; +} + +STDMETHODIMP CDocumentMgr::QueryInterface(REFIID iid, LPVOID *ppvObject) +{ + TRACE("%p -> (%s, %p)\n", this, wine_dbgstr_guid(&iid), ppvObject); + *ppvObject = NULL; + + if (iid == IID_IUnknown || iid == IID_ITfDocumentMgr) + *ppvObject = static_cast(this); + else if (iid == IID_ITfSource) + *ppvObject = static_cast(this); + else if (iid == IID_ITfCompartmentMgr) + *ppvObject = m_pCompartmentMgr; + + if (*ppvObject) + { + AddRef(); + return S_OK; + } + + ERR("E_NOINTERFACE: %s\n", wine_dbgstr_guid(&iid)); + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CDocumentMgr::AddRef() +{ + TRACE("%p -> ()\n", this); + return ::InterlockedIncrement(&m_cRefs); +} + +STDMETHODIMP_(ULONG) CDocumentMgr::Release() +{ + TRACE("%p -> ()\n", this); + ULONG ret = ::InterlockedDecrement(&m_cRefs); + if (!ret) + delete this; + return ret; +} + +STDMETHODIMP +CDocumentMgr::CreateContext( + TfClientId tidOwner, + DWORD dwFlags, + IUnknown *punk, + ITfContext **ppic, + TfEditCookie *pecTextStore) +{ + TRACE("%p -> (%d, 0x%lX, %p, %p, %p)\n", this, tidOwner, dwFlags, punk, ppic, pecTextStore); + return Context_Constructor(tidOwner, punk, this, ppic, pecTextStore); +} + +STDMETHODIMP CDocumentMgr::Push(ITfContext *pic) +{ + TRACE("%p -> (%p)\n", this, pic); + + if (m_contextStack[1]) /* Full */ + { + ERR("TF_E_STACKFULL\n"); + return TF_E_STACKFULL; + } + + if (!pic) + { + ERR("!pic\n"); + return E_INVALIDARG; + } + + ITfContext *check; + HRESULT hr = pic->QueryInterface(IID_ITfContext, reinterpret_cast(&check)); + if (FAILED(hr)) + { + ERR("hr: 0x%lX\n", hr); + return E_INVALIDARG; + } + + if (!m_contextStack[0]) + m_pThreadMgrSink->OnInitDocumentMgr(this); + + m_contextStack[1] = m_contextStack[0]; + m_contextStack[0] = check; + + Context_Initialize(check, this); + m_pThreadMgrSink->OnPushContext(check); + + return S_OK; +} + +STDMETHODIMP CDocumentMgr::Pop(DWORD dwFlags) +{ + TRACE("%p -> (0x%lX)\n", this, dwFlags); + + if (dwFlags == TF_POPF_ALL) + { + for (SIZE_T i = 0; i < _countof(m_contextStack); i++) + { + if (!m_contextStack[i]) + continue; + + m_pThreadMgrSink->OnPopContext(m_contextStack[i]); + Context_Uninitialize(m_contextStack[i]); + m_contextStack[i]->Release(); + m_contextStack[i] = NULL; + } + + m_pThreadMgrSink->OnUninitDocumentMgr(this); + return S_OK; + } + + if (dwFlags) + { + ERR("E_INVALIDARG: 0x%lX\n", dwFlags); + return E_INVALIDARG; + } + + if (!m_contextStack[1]) // Cannot pop last context + { + ERR("!m_contextStack[1]\n"); + return E_FAIL; + } + + m_pThreadMgrSink->OnPopContext(m_contextStack[0]); + Context_Uninitialize(m_contextStack[0]); + + if (m_contextStack[0]) + m_contextStack[0]->Release(); + + m_contextStack[0] = m_contextStack[1]; + m_contextStack[1] = NULL; + + if (!m_contextStack[0]) + m_pThreadMgrSink->OnUninitDocumentMgr(this); + + return S_OK; +} + +STDMETHODIMP CDocumentMgr::GetTop(ITfContext **ppic) +{ + TRACE("%p -> (%p)\n", this, ppic); + + if (!ppic) + { + ERR("!ppic\n"); + return E_INVALIDARG; + } + + if (m_contextStack[0]) + m_contextStack[0]->AddRef(); + + *ppic = m_contextStack[0]; + return S_OK; +} + +STDMETHODIMP CDocumentMgr::GetBase(ITfContext **ppic) +{ + TRACE("%p -> (%p)\n", this, ppic); + + if (!ppic) + { + ERR("!ppic\n"); + return E_INVALIDARG; + } + + ITfContext *target = (m_contextStack[1] ? m_contextStack[1] : m_contextStack[0]); + *ppic = target; + if (target) + target->AddRef(); + return S_OK; +} + +STDMETHODIMP CDocumentMgr::EnumContexts(IEnumTfContexts **ppEnum) +{ + TRACE("%p -> (%p)\n", this, ppEnum); + return EnumTfContext_Constructor(this, ppEnum); +} + +STDMETHODIMP CDocumentMgr::AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie) +{ + TRACE("%p -> (%s, %p, %p)\n", this, wine_dbgstr_guid(&riid), punk, pdwCookie); + + if (!punk || !pdwCookie) + return E_INVALIDARG; + + if (riid != IID_ITfTransitoryExtensionSink) + { + FIXME("E_NOTIMPL: %s\n", wine_dbgstr_guid(&riid)); + return E_NOTIMPL; + } + + return advise_sink(&m_transitoryExtensionSink, IID_ITfTransitoryExtensionSink, + COOKIE_MAGIC_DMSINK, punk, pdwCookie); + +} + +STDMETHODIMP CDocumentMgr::UnadviseSink(DWORD pdwCookie) +{ + TRACE("%p -> (%p)\n", this, pdwCookie); + + if (get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_DMSINK) + return E_INVALIDARG; + + return unadvise_sink(pdwCookie); +} + +//////////////////////////////////////////////////////////////////////////// +// CEnumTfContext + +CEnumTfContext::CEnumTfContext(_In_opt_ CDocumentMgr *mgr) + : m_cRefs(1) + , m_index(0) + , m_pDocMgr(mgr) +{ + if (mgr) + mgr->AddRef(); +} + +CEnumTfContext::~CEnumTfContext() +{ + if (m_pDocMgr) + { + m_pDocMgr->Release(); + m_pDocMgr = NULL; + } +} + +HRESULT CEnumTfContext::CreateInstance(_In_opt_ CDocumentMgr *mgr, _Out_ IEnumTfContexts **ppOut) +{ + if (!ppOut) + { + ERR("!ppOut\n"); + return E_POINTER; + } + + CEnumTfContext *This = new(cicNoThrow) CEnumTfContext(mgr); + if (This == NULL) + { + ERR("E_OUTOFMEMORY\n"); + return E_OUTOFMEMORY; + } + + *ppOut = static_cast(This); + TRACE("returning %p\n", *ppOut); + return S_OK; +} + +STDMETHODIMP CEnumTfContext::QueryInterface(REFIID iid, LPVOID *ppvObject) +{ + TRACE("%p -> (%s, %p)\n", this, wine_dbgstr_guid(&iid), ppvObject); + + *ppvObject = NULL; + + if (iid == IID_IUnknown || iid == IID_IEnumTfContexts) + *ppvObject = static_cast(this); + + if (*ppvObject) + { + AddRef(); + return S_OK; + } + + WARN("E_NOINTERFACE: %s\n", wine_dbgstr_guid(&iid)); + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CEnumTfContext::AddRef() +{ + TRACE("%p -> ()\n", this); + return ::InterlockedIncrement(&m_cRefs); +} + +STDMETHODIMP_(ULONG) CEnumTfContext::Release() +{ + TRACE("%p -> ()\n", this); + ULONG ret = ::InterlockedDecrement(&m_cRefs); + if (!ret) + delete this; + return ret; +} + +STDMETHODIMP CEnumTfContext::Next(ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched) +{ + TRACE("%p -> (%lu, %p, %p)\n",this, ulCount, rgContext, pcFetched); + + if (!rgContext) + { + ERR("!rgContext\n"); + return E_POINTER; + } + + ULONG fetched; + for (fetched = 0; fetched < ulCount; ++fetched, ++m_index, ++rgContext) + { + if (m_index >= _countof(m_pDocMgr->m_contextStack)) + break; + + if (!m_pDocMgr->m_contextStack[m_index]) + break; + + *rgContext = m_pDocMgr->m_contextStack[m_index]; + (*rgContext)->AddRef(); + } + + if (pcFetched) + *pcFetched = fetched; + + return (fetched == ulCount) ? S_OK : S_FALSE; +} + +STDMETHODIMP CEnumTfContext::Skip(ULONG celt) +{ + TRACE("%p -> (%lu)\n", this, celt); + m_index += celt; + return S_OK; +} + +STDMETHODIMP CEnumTfContext::Reset() +{ + TRACE("%p -> ()\n", this); + m_index = 0; + return S_OK; +} + +STDMETHODIMP CEnumTfContext::Clone(IEnumTfContexts **ppenum) +{ + TRACE("%p -> (%p)\n", this, ppenum); + + if (!ppenum) + { + ERR("!ppenum\n"); + return E_POINTER; + } + + CEnumTfContext *This = new(cicNoThrow) CEnumTfContext(m_pDocMgr); + if (!This) + { + ERR("E_OUTOFMEMORY\n"); + return E_OUTOFMEMORY; + } + + This->m_index = m_index; + *ppenum = This; + return S_OK; +} + +//////////////////////////////////////////////////////////////////////////// + +EXTERN_C +HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *pThreadMgrSink, ITfDocumentMgr **ppOut) +{ + return CDocumentMgr::CreateInstance(pThreadMgrSink, ppOut); +} + +EXTERN_C +HRESULT EnumTfContext_Constructor(CDocumentMgr *mgr, IEnumTfContexts **ppOut) +{ + return CEnumTfContext::CreateInstance(mgr, ppOut); +} diff --git a/base/ctf/msctf/documentmgr.h b/base/ctf/msctf/documentmgr.h new file mode 100644 index 00000000000..26296338e58 --- /dev/null +++ b/base/ctf/msctf/documentmgr.h @@ -0,0 +1,86 @@ +/* + * PROJECT: ReactOS CTF + * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) + * PURPOSE: Implementation of ITfDocumentMgr and IEnumTfContexts + * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers + * Copyright 2025 Katayama Hirofumi MZ + */ + +#pragma once + +//////////////////////////////////////////////////////////////////////////// +// CDocumentMgr + +class CDocumentMgr + : public ITfDocumentMgr + , public ITfSource +{ +public: + CDocumentMgr(ITfThreadMgrEventSink *threadMgrSink); + virtual ~CDocumentMgr(); + + static HRESULT + CreateInstance( + _In_ ITfThreadMgrEventSink *pThreadMgrSink, + _Out_ ITfDocumentMgr **ppOut); + + // ** IUnknown methods ** + STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObject) override; + STDMETHODIMP_(ULONG) AddRef() override; + STDMETHODIMP_(ULONG) Release() override; + + // ** ITfDocumentMgr methods ** + STDMETHODIMP CreateContext( + TfClientId tidOwner, + DWORD dwFlags, + IUnknown *punk, + ITfContext **ppic, + TfEditCookie *pecTextStore) override; + STDMETHODIMP Push(ITfContext *pic) override; + STDMETHODIMP Pop(DWORD dwFlags) override; + STDMETHODIMP GetTop(ITfContext **ppic) override; + STDMETHODIMP GetBase(ITfContext **ppic) override; + STDMETHODIMP EnumContexts(IEnumTfContexts **ppEnum) override; + + // ** ITfSource methods ** + STDMETHODIMP AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie) override; + STDMETHODIMP UnadviseSink(DWORD pdwCookie) override; + + friend class CEnumTfContext; + +protected: + LONG m_cRefs; + ITfCompartmentMgr *m_pCompartmentMgr; + ITfContext *m_contextStack[2]; // limit of 2 contexts + ITfThreadMgrEventSink *m_pThreadMgrSink; + struct list m_transitoryExtensionSink; +}; + +//////////////////////////////////////////////////////////////////////////// +// CEnumTfContext + +class CEnumTfContext + : public IEnumTfContexts +{ +public: + CEnumTfContext(_In_opt_ CDocumentMgr *mgr); + virtual ~CEnumTfContext(); + + static HRESULT CreateInstance(_In_opt_ CDocumentMgr *mgr, _Out_ IEnumTfContexts **ppOut); + + // ** IUnknown methods ** + STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObject) override; + STDMETHODIMP_(ULONG) AddRef() override; + STDMETHODIMP_(ULONG) Release() override; + + // ** IEnumTfContexts methods ** + STDMETHODIMP Next(ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched) override; + STDMETHODIMP Skip(ULONG celt) override; + STDMETHODIMP Reset() override; + STDMETHODIMP Clone(IEnumTfContexts **ppenum) override; + +protected: + LONG m_cRefs; + DWORD m_index; + CDocumentMgr *m_pDocMgr; +};