reactos/base/ctf/msctf/documentmgr.cpp
Katayama Hirofumi MZ e26ad0de12
[MSCTF] Translate ITfDocumentMgr into C++ (#8120)
Implementing missing features...
JIRA issue: CORE-19361
- Delete documentmgr.c and add
  documentmgr.cpp.
- Make ITfDocumentMgr and
  IEnumTfContexts C++ code.
2025-06-17 07:08:42 +09:00

461 lines
10 KiB
C++

/*
* 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 <katayama.hirofumi.mz@gmail.com>
*/
#include <initguid.h>
#include <windef.h>
#include <winbase.h>
#include <oleauto.h>
#include <msctf.h>
#include <msctf_undoc.h>
#include <wine/list.h>
// Cicero
#include <cicbase.h>
#include "documentmgr.h"
#include "msctf_internal.h"
#include <wine/debug.h>
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<ITfDocumentMgr *>(this);
ITfCompartmentMgr **ppCompMgr = static_cast<ITfCompartmentMgr **>(&m_pCompartmentMgr);
CompartmentMgr_Constructor(pDocMgr, IID_IUnknown, reinterpret_cast<IUnknown **>(ppCompMgr));
}
CDocumentMgr::~CDocumentMgr()
{
TRACE("destroying %p\n", this);
ITfThreadMgr *tm = NULL;
TF_GetThreadMgr(&tm);
if (tm)
{
ThreadMgr_OnDocumentMgrDestruction(tm, static_cast<ITfDocumentMgr*>(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<ITfDocumentMgr *>(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<ITfDocumentMgr *>(this);
else if (iid == IID_ITfSource)
*ppvObject = static_cast<ITfSource *>(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<LPVOID *>(&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<IEnumTfContexts *>(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<IEnumTfContexts *>(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);
}