mirror of
https://github.com/reactos/reactos.git
synced 2025-07-08 16:07:51 +00:00

Follow-up of #8224. JIRA issue: CORE-19361 - Add cicIsNullPtr function in Cicero <cicbase.h>. - Reordering of CMakeLists.txt items. - Minor refactoring.
1009 lines
26 KiB
C++
1009 lines
26 KiB
C++
/*
|
|
* PROJECT: ReactOS CTF
|
|
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
|
|
* PURPOSE: ITfContext implementation
|
|
* 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 <winreg.h>
|
|
#include <cguid.h>
|
|
#include <olectl.h>
|
|
#include <oleauto.h>
|
|
#include <msctf.h>
|
|
#include <msctf_undoc.h>
|
|
|
|
// Cicero
|
|
#include <cicbase.h>
|
|
#include <cicreg.h>
|
|
#include <cicutb.h>
|
|
|
|
#include "msctf_internal.h"
|
|
|
|
#include <wine/debug.h>
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msctf);
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CContext
|
|
: public ITfContext
|
|
, public ITfSource
|
|
// , public ITfContextComposition
|
|
, public ITfContextOwnerCompositionServices
|
|
// , public ITfContextOwnerServices
|
|
, public ITfInsertAtSelection
|
|
// , public ITfMouseTracker
|
|
// , public ITfQueryEmbedded
|
|
, public ITfSourceSingle
|
|
, public ITextStoreACPSink
|
|
, public ITextStoreACPServices
|
|
{
|
|
public:
|
|
CContext();
|
|
virtual ~CContext();
|
|
|
|
static HRESULT CreateInstance(
|
|
TfClientId tidOwner,
|
|
IUnknown *punk,
|
|
ITfDocumentMgr *mgr,
|
|
ITfContext **ppOut,
|
|
TfEditCookie *pecTextStore);
|
|
HRESULT Initialize(ITfDocumentMgr *manager);
|
|
HRESULT Uninitialize();
|
|
|
|
// ** IUnknown methods **
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override;
|
|
STDMETHODIMP_(ULONG) AddRef() override;
|
|
STDMETHODIMP_(ULONG) Release() override;
|
|
|
|
// ** ITfContext methods **
|
|
STDMETHODIMP RequestEditSession(
|
|
_In_ TfClientId tid,
|
|
_In_ ITfEditSession *pes,
|
|
_In_ DWORD dwFlags,
|
|
_Out_ HRESULT *phrSession) override;
|
|
STDMETHODIMP InWriteSession(
|
|
_In_ TfClientId tid,
|
|
_Out_ BOOL *pfWriteSession) override;
|
|
STDMETHODIMP GetSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ ULONG ulIndex,
|
|
_In_ ULONG ulCount,
|
|
_Out_ TF_SELECTION *pSelection,
|
|
_Out_ ULONG *pcFetched) override;
|
|
STDMETHODIMP SetSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ ULONG ulCount,
|
|
_In_ const TF_SELECTION *pSelection) override;
|
|
STDMETHODIMP GetStart(
|
|
_In_ TfEditCookie ec,
|
|
_Out_ ITfRange **ppStart) override;
|
|
STDMETHODIMP GetEnd(
|
|
_In_ TfEditCookie ec,
|
|
_Out_ ITfRange **ppEnd) override;
|
|
STDMETHODIMP GetActiveView(_Out_ ITfContextView **ppView) override;
|
|
STDMETHODIMP EnumViews(_Out_ IEnumTfContextViews **ppEnum) override;
|
|
STDMETHODIMP GetStatus(_Out_ TF_STATUS *pdcs) override;
|
|
STDMETHODIMP GetProperty(
|
|
_In_ REFGUID guidProp,
|
|
_Out_ ITfProperty **ppProp) override;
|
|
STDMETHODIMP GetAppProperty(
|
|
_In_ REFGUID guidProp,
|
|
_Out_ ITfReadOnlyProperty **ppProp) override;
|
|
STDMETHODIMP TrackProperties(
|
|
_In_ const GUID **prgProp,
|
|
_In_ ULONG cProp,
|
|
_In_ const GUID **prgAppProp,
|
|
_In_ ULONG cAppProp,
|
|
_Out_ ITfReadOnlyProperty **ppProperty) override;
|
|
STDMETHODIMP EnumProperties(_Out_ IEnumTfProperties **ppEnum) override;
|
|
STDMETHODIMP GetDocumentMgr(_Out_ ITfDocumentMgr **ppDm) override;
|
|
STDMETHODIMP CreateRangeBackup(
|
|
_In_ TfEditCookie ec,
|
|
_In_ ITfRange *pRange,
|
|
_Out_ ITfRangeBackup **ppBackup) override;
|
|
|
|
// ** ITfSource methods **
|
|
STDMETHODIMP AdviseSink(
|
|
_In_ REFIID riid,
|
|
_In_ IUnknown *punk,
|
|
_Out_ DWORD *pdwCookie) override;
|
|
STDMETHODIMP UnadviseSink(_In_ DWORD dwCookie) override;
|
|
|
|
// ** ITfContextOwnerCompositionServices methods **
|
|
STDMETHODIMP StartComposition(
|
|
_In_ TfEditCookie ecWrite,
|
|
_In_ ITfRange *pCompositionRange,
|
|
_In_ ITfCompositionSink *pSink,
|
|
_Out_ ITfComposition **ppComposition);
|
|
STDMETHODIMP EnumCompositions(_Out_ IEnumITfCompositionView **ppEnum);
|
|
STDMETHODIMP FindComposition(
|
|
_In_ TfEditCookie ecRead,
|
|
_In_ ITfRange *pTestRange,
|
|
_Out_ IEnumITfCompositionView **ppEnum);
|
|
STDMETHODIMP TakeOwnership(
|
|
_In_ TfEditCookie ecWrite,
|
|
_In_ ITfCompositionView *pComposition,
|
|
_In_ ITfCompositionSink *pSink,
|
|
_Out_ ITfComposition **ppComposition);
|
|
STDMETHODIMP TerminateComposition(_In_ ITfCompositionView *pComposition) override;
|
|
|
|
// ** ITfInsertAtSelection methods **
|
|
STDMETHODIMP InsertTextAtSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ DWORD dwFlags,
|
|
_In_ const WCHAR *pchText,
|
|
_In_ LONG cch,
|
|
_Out_ ITfRange **ppRange) override;
|
|
STDMETHODIMP InsertEmbeddedAtSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ DWORD dwFlags,
|
|
_In_ IDataObject *pDataObject,
|
|
_Out_ ITfRange **ppRange) override;
|
|
|
|
// ** ITfSourceSingle methods **
|
|
STDMETHODIMP AdviseSingleSink(
|
|
_In_ TfClientId tid,
|
|
_In_ REFIID riid,
|
|
_In_ IUnknown *punk) override;
|
|
STDMETHODIMP UnadviseSingleSink(
|
|
_In_ TfClientId tid,
|
|
_In_ REFIID riid) override;
|
|
|
|
// ** ITextStoreACPSink methods **
|
|
STDMETHODIMP OnTextChange(
|
|
_In_ DWORD dwFlags,
|
|
_In_ const TS_TEXTCHANGE *pChange) override;
|
|
STDMETHODIMP OnSelectionChange() override;
|
|
STDMETHODIMP OnLayoutChange(
|
|
_In_ TsLayoutCode lcode,
|
|
_In_ TsViewCookie vcView) override;
|
|
STDMETHODIMP OnStatusChange(_In_ DWORD dwFlags) override;
|
|
STDMETHODIMP OnAttrsChange(
|
|
_In_ LONG acpStart,
|
|
_In_ LONG acpEnd,
|
|
_In_ ULONG cAttrs,
|
|
_In_ const TS_ATTRID *paAttrs) override;
|
|
STDMETHODIMP OnLockGranted(_In_ DWORD dwLockFlags) override;
|
|
STDMETHODIMP OnStartEditTransaction() override;
|
|
STDMETHODIMP OnEndEditTransaction() override;
|
|
|
|
// ** ITextStoreACPServices methods **
|
|
STDMETHODIMP Serialize(
|
|
_In_ ITfProperty *prop,
|
|
_In_ ITfRange *range,
|
|
_Out_ TF_PERSISTENT_PROPERTY_HEADER_ACP *header,
|
|
_In_ IStream *stream) override;
|
|
STDMETHODIMP Unserialize(
|
|
_In_ ITfProperty *prop,
|
|
_In_ const TF_PERSISTENT_PROPERTY_HEADER_ACP *header,
|
|
_In_ IStream *stream,
|
|
_In_ ITfPersistentPropertyLoaderACP *loader) override;
|
|
STDMETHODIMP ForceLoadProperty(_In_ ITfProperty *prop) override;
|
|
STDMETHODIMP CreateRange(
|
|
_In_ LONG start,
|
|
_In_ LONG end,
|
|
_Out_ ITfRangeACP **range) override;
|
|
|
|
protected:
|
|
LONG m_cRefs;
|
|
BOOL m_connected;
|
|
|
|
// Aggregation
|
|
ITfCompartmentMgr *m_CompartmentMgr;
|
|
|
|
TfClientId m_tidOwner;
|
|
TfEditCookie m_defaultCookie;
|
|
TS_STATUS m_documentStatus;
|
|
ITfDocumentMgr *m_manager;
|
|
|
|
ITextStoreACP *m_pITextStoreACP;
|
|
ITfContextOwnerCompositionSink *m_pITfContextOwnerCompositionSink;
|
|
ITfEditSession *m_currentEditSession;
|
|
|
|
// kept as separate lists to reduce unnecessary iterations
|
|
struct list m_pContextKeyEventSink;
|
|
struct list m_pEditTransactionSink;
|
|
struct list m_pStatusSink;
|
|
struct list m_pTextEditSink;
|
|
struct list m_pTextLayoutSink;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct tagEditCookie
|
|
{
|
|
DWORD lockType;
|
|
CContext *pOwningContext;
|
|
} EditCookie;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
CContext::CContext()
|
|
: m_cRefs(1)
|
|
, m_connected(FALSE)
|
|
, m_CompartmentMgr(NULL)
|
|
, m_manager(NULL)
|
|
, m_pITextStoreACP(NULL)
|
|
, m_pITfContextOwnerCompositionSink(NULL)
|
|
, m_currentEditSession(NULL)
|
|
{
|
|
list_init(&m_pContextKeyEventSink);
|
|
list_init(&m_pEditTransactionSink);
|
|
list_init(&m_pStatusSink);
|
|
list_init(&m_pTextEditSink);
|
|
list_init(&m_pTextLayoutSink);
|
|
}
|
|
|
|
CContext::~CContext()
|
|
{
|
|
EditCookie *cookie;
|
|
TRACE("destroying %p\n", this);
|
|
|
|
if (m_pITextStoreACP)
|
|
m_pITextStoreACP->Release();
|
|
|
|
if (m_pITfContextOwnerCompositionSink)
|
|
m_pITfContextOwnerCompositionSink->Release();
|
|
|
|
if (m_defaultCookie)
|
|
{
|
|
cookie = (EditCookie *)remove_Cookie(m_defaultCookie);
|
|
HeapFree(GetProcessHeap(), 0, cookie);
|
|
m_defaultCookie = 0;
|
|
}
|
|
|
|
free_sinks(&m_pContextKeyEventSink);
|
|
free_sinks(&m_pEditTransactionSink);
|
|
free_sinks(&m_pStatusSink);
|
|
free_sinks(&m_pTextEditSink);
|
|
free_sinks(&m_pTextLayoutSink);
|
|
|
|
if (m_CompartmentMgr)
|
|
m_CompartmentMgr->Release();
|
|
}
|
|
|
|
STDMETHODIMP CContext::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
|
|
if (riid == IID_IUnknown || riid == IID_ITfContext)
|
|
*ppvObj = static_cast<ITfContext *>(this);
|
|
else if (riid == IID_ITfSource)
|
|
*ppvObj = static_cast<ITfSource *>(this);
|
|
else if (riid == IID_ITfContextOwnerCompositionServices)
|
|
*ppvObj = static_cast<ITfContextOwnerCompositionServices *>(this);
|
|
else if (riid == IID_ITfInsertAtSelection)
|
|
*ppvObj = static_cast<ITfInsertAtSelection *>(this);
|
|
else if (riid == IID_ITfCompartmentMgr)
|
|
*ppvObj = m_CompartmentMgr;
|
|
else if (riid == IID_ITfSourceSingle)
|
|
*ppvObj = static_cast<ITfSourceSingle *>(this);
|
|
else if (riid == IID_ITextStoreACPSink)
|
|
*ppvObj = static_cast<ITextStoreACPSink *>(this);
|
|
else if (riid == IID_ITextStoreACPServices)
|
|
*ppvObj = static_cast<ITextStoreACPServices *>(this);
|
|
|
|
if (*ppvObj)
|
|
{
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("unsupported interface: %s\n", debugstr_guid(&riid));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CContext::AddRef()
|
|
{
|
|
return ::InterlockedIncrement(&m_cRefs);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CContext::Release()
|
|
{
|
|
ULONG ret = ::InterlockedDecrement(&m_cRefs);
|
|
if (!ret)
|
|
delete this;
|
|
return ret;
|
|
}
|
|
|
|
STDMETHODIMP CContext::RequestEditSession(
|
|
_In_ TfClientId tid,
|
|
_In_ ITfEditSession *pes,
|
|
_In_ DWORD dwFlags,
|
|
_Out_ HRESULT *phrSession)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwLockFlags = 0x0;
|
|
|
|
TRACE("(%p) %i %p %x %p\n", this, tid, pes, dwFlags, phrSession);
|
|
|
|
if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE))
|
|
{
|
|
*phrSession = E_FAIL;
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("No ITextStoreACP available\n");
|
|
*phrSession = E_FAIL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!(dwFlags & TF_ES_ASYNC))
|
|
dwLockFlags |= TS_LF_SYNC;
|
|
|
|
if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE)
|
|
dwLockFlags |= TS_LF_READWRITE;
|
|
else if (dwFlags & TF_ES_READ)
|
|
dwLockFlags |= TS_LF_READ;
|
|
|
|
if (!m_documentStatus.dwDynamicFlags)
|
|
m_pITextStoreACP->GetStatus(&m_documentStatus);
|
|
|
|
if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) &&
|
|
(m_documentStatus.dwDynamicFlags & TS_SD_READONLY))
|
|
{
|
|
*phrSession = TS_E_READONLY;
|
|
return S_OK;
|
|
}
|
|
|
|
hr = pes->QueryInterface(IID_ITfEditSession, (LPVOID *)&m_currentEditSession);
|
|
if (FAILED(hr))
|
|
{
|
|
*phrSession = E_FAIL;
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return m_pITextStoreACP->RequestLock(dwLockFlags, phrSession);
|
|
}
|
|
|
|
STDMETHODIMP CContext::InWriteSession(
|
|
_In_ TfClientId tid,
|
|
_Out_ BOOL *pfWriteSession)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::GetSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ ULONG ulIndex,
|
|
_In_ ULONG ulCount,
|
|
_Out_ TF_SELECTION *pSelection,
|
|
_Out_ ULONG *pcFetched)
|
|
{
|
|
EditCookie *cookie;
|
|
ULONG count, i;
|
|
ULONG totalFetched = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pSelection || !pcFetched)
|
|
return E_INVALIDARG;
|
|
|
|
*pcFetched = 0;
|
|
|
|
if (!m_connected)
|
|
return TF_E_DISCONNECTED;
|
|
|
|
if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE)
|
|
return TF_E_NOLOCK;
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("Context does not have a ITextStoreACP\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
cookie = (EditCookie *)get_Cookie_data(ec);
|
|
|
|
count = (ulIndex == (ULONG)TF_DEFAULT_SELECTION) ? 1 : ulCount;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
DWORD fetched;
|
|
TS_SELECTION_ACP acps;
|
|
|
|
hr = m_pITextStoreACP->GetSelection(ulIndex + i, 1, &acps, &fetched);
|
|
if (hr == TS_E_NOLOCK)
|
|
return TF_E_NOLOCK;
|
|
else if (FAILED(hr))
|
|
break;
|
|
|
|
pSelection[totalFetched].style.ase = (TfActiveSelEnd)acps.style.ase;
|
|
pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar;
|
|
Range_Constructor(this, m_pITextStoreACP, cookie->lockType, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range);
|
|
totalFetched++;
|
|
}
|
|
|
|
*pcFetched = totalFetched;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CContext::SetSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ ULONG ulCount,
|
|
_In_ const TF_SELECTION *pSelection)
|
|
{
|
|
TS_SELECTION_ACP *acp;
|
|
ULONG i;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p) %i %i %p\n", this, ec, ulCount, pSelection);
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("Context does not have a ITextStoreACP\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE)
|
|
return TF_E_NOLOCK;
|
|
|
|
acp = (TS_SELECTION_ACP *)HeapAlloc(GetProcessHeap(), 0, sizeof(TS_SELECTION_ACP) * ulCount);
|
|
if (!acp)
|
|
return E_OUTOFMEMORY;
|
|
|
|
for (i = 0; i < ulCount; i++)
|
|
{
|
|
if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i])))
|
|
{
|
|
TRACE("Selection Conversion Failed\n");
|
|
HeapFree(GetProcessHeap(), 0 , acp);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
hr = m_pITextStoreACP->SetSelection(ulCount, acp);
|
|
|
|
HeapFree(GetProcessHeap(), 0, acp);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CContext::GetStart(
|
|
_In_ TfEditCookie ec,
|
|
_Out_ ITfRange **ppStart)
|
|
{
|
|
EditCookie *cookie;
|
|
TRACE("(%p) %i %p\n", this, ec, ppStart);
|
|
|
|
if (!ppStart)
|
|
return E_INVALIDARG;
|
|
|
|
*ppStart = NULL;
|
|
|
|
if (!m_connected)
|
|
return TF_E_DISCONNECTED;
|
|
|
|
if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE)
|
|
return TF_E_NOLOCK;
|
|
|
|
cookie = (EditCookie *)get_Cookie_data(ec);
|
|
return Range_Constructor(this, m_pITextStoreACP, cookie->lockType, 0, 0, ppStart);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CContext::GetEnd(
|
|
_In_ TfEditCookie ec,
|
|
_Out_ ITfRange **ppEnd)
|
|
{
|
|
EditCookie *cookie;
|
|
LONG end;
|
|
|
|
TRACE("(%p) %i %p\n", this, ec, ppEnd);
|
|
|
|
if (!ppEnd)
|
|
return E_INVALIDARG;
|
|
|
|
*ppEnd = NULL;
|
|
|
|
if (!m_connected)
|
|
return TF_E_DISCONNECTED;
|
|
|
|
if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE)
|
|
return TF_E_NOLOCK;
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("Context does not have a ITextStoreACP\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
cookie = (EditCookie *)get_Cookie_data(ec);
|
|
m_pITextStoreACP->GetEndACP(&end);
|
|
|
|
return Range_Constructor(this, m_pITextStoreACP, cookie->lockType, end, end, ppEnd);
|
|
}
|
|
|
|
STDMETHODIMP CContext::GetActiveView(_Out_ ITfContextView **ppView)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::EnumViews(_Out_ IEnumTfContextViews **ppEnum)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::GetStatus(_Out_ TF_STATUS *pdcs)
|
|
{
|
|
TRACE("(%p) %p\n", this, pdcs);
|
|
|
|
if (!m_connected)
|
|
return TF_E_DISCONNECTED;
|
|
|
|
if (!pdcs)
|
|
return E_INVALIDARG;
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("Context does not have a ITextStoreACP\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
m_pITextStoreACP->GetStatus(&m_documentStatus);
|
|
|
|
*pdcs = m_documentStatus;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CContext::GetProperty(
|
|
_In_ REFGUID guidProp,
|
|
_Out_ ITfProperty **ppProp)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::GetAppProperty(
|
|
_In_ REFGUID guidProp,
|
|
_Out_ ITfReadOnlyProperty **ppProp)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::TrackProperties(
|
|
_In_ const GUID **prgProp,
|
|
_In_ ULONG cProp,
|
|
_In_ const GUID **prgAppProp,
|
|
_In_ ULONG cAppProp,
|
|
_Out_ ITfReadOnlyProperty **ppProperty)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::EnumProperties(_Out_ IEnumTfProperties **ppEnum)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::GetDocumentMgr(_Out_ ITfDocumentMgr **ppDm)
|
|
{
|
|
TRACE("(%p) %p\n", this, ppDm);
|
|
|
|
if (!ppDm)
|
|
return E_INVALIDARG;
|
|
|
|
*ppDm = m_manager;
|
|
if (!m_manager)
|
|
return S_FALSE;
|
|
|
|
m_manager->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CContext::CreateRangeBackup(
|
|
_In_ TfEditCookie ec,
|
|
_In_ ITfRange *pRange,
|
|
_Out_ ITfRangeBackup **ppBackup)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::AdviseSink(
|
|
_In_ REFIID riid,
|
|
_In_ IUnknown *punk,
|
|
_Out_ DWORD *pdwCookie)
|
|
{
|
|
TRACE("(%p) %s %p %p\n", this, debugstr_guid(&riid), punk, pdwCookie);
|
|
|
|
if (cicIsNullPtr(&riid) || !punk || !pdwCookie)
|
|
return E_INVALIDARG;
|
|
|
|
if (riid == IID_ITfTextEditSink)
|
|
return advise_sink(&m_pTextEditSink, IID_ITfTextEditSink, COOKIE_MAGIC_CONTEXTSINK, punk, pdwCookie);
|
|
|
|
FIXME("(%p) Unhandled Sink: %s\n", this, debugstr_guid(&riid));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::UnadviseSink(_In_ DWORD dwCookie)
|
|
{
|
|
TRACE("(%p) %x\n", this, dwCookie);
|
|
|
|
if (get_Cookie_magic(dwCookie) != COOKIE_MAGIC_CONTEXTSINK)
|
|
return E_INVALIDARG;
|
|
|
|
return unadvise_sink(dwCookie);
|
|
}
|
|
|
|
STDMETHODIMP CContext::StartComposition(
|
|
_In_ TfEditCookie ecWrite,
|
|
_In_ ITfRange *pCompositionRange,
|
|
_In_ ITfCompositionSink *pSink,
|
|
_Out_ ITfComposition **ppComposition)
|
|
{
|
|
FIXME("STUB:(%p) %#x %p %p %p\n", this, ecWrite, pCompositionRange, pSink, ppComposition);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::EnumCompositions(_Out_ IEnumITfCompositionView **ppEnum)
|
|
{
|
|
FIXME("STUB:(%p) %p\n", this, ppEnum);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::FindComposition(
|
|
_In_ TfEditCookie ecRead,
|
|
_In_ ITfRange *pTestRange,
|
|
_Out_ IEnumITfCompositionView **ppEnum)
|
|
{
|
|
FIXME("STUB:(%p) %#x %p %p\n", this, ecRead, pTestRange, ppEnum);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::TakeOwnership(
|
|
_In_ TfEditCookie ecWrite,
|
|
_In_ ITfCompositionView *pComposition,
|
|
_In_ ITfCompositionSink *pSink,
|
|
_Out_ ITfComposition **ppComposition)
|
|
{
|
|
FIXME("STUB:(%p) %#x %p %p %p\n", this, ecWrite, pComposition, pSink, ppComposition);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::TerminateComposition(_In_ ITfCompositionView *pComposition)
|
|
{
|
|
FIXME("STUB:(%p) %p\n", this, pComposition);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::InsertTextAtSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ DWORD dwFlags,
|
|
_In_ const WCHAR *pchText,
|
|
_In_ LONG cch,
|
|
_Out_ ITfRange **ppRange)
|
|
{
|
|
EditCookie *cookie;
|
|
LONG acpStart, acpEnd;
|
|
TS_TEXTCHANGE change;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p) %i %x %s %p\n", this, ec, dwFlags, debugstr_wn(pchText,cch), ppRange);
|
|
|
|
if (!m_connected)
|
|
return TF_E_DISCONNECTED;
|
|
|
|
if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE)
|
|
return TF_E_NOLOCK;
|
|
|
|
cookie = (EditCookie *)get_Cookie_data(ec);
|
|
|
|
if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE)
|
|
return TS_E_READONLY;
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("Context does not have a ITextStoreACP\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
hr = m_pITextStoreACP->InsertTextAtSelection(dwFlags, pchText, cch, &acpStart, &acpEnd, &change);
|
|
if (SUCCEEDED(hr))
|
|
Range_Constructor(this, m_pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CContext::InsertEmbeddedAtSelection(
|
|
_In_ TfEditCookie ec,
|
|
_In_ DWORD dwFlags,
|
|
_In_ IDataObject *pDataObject,
|
|
_Out_ ITfRange **ppRange)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::AdviseSingleSink(
|
|
_In_ TfClientId tid,
|
|
_In_ REFIID riid,
|
|
_In_ IUnknown *punk)
|
|
{
|
|
FIXME("STUB:(%p) %i %s %p\n", this, tid, debugstr_guid(&riid), punk);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::UnadviseSingleSink(
|
|
_In_ TfClientId tid,
|
|
_In_ REFIID riid)
|
|
{
|
|
FIXME("STUB:(%p) %i %s\n", this, tid, debugstr_guid(&riid));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnTextChange(
|
|
_In_ DWORD dwFlags,
|
|
_In_ const TS_TEXTCHANGE *pChange)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnSelectionChange()
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnLayoutChange(
|
|
_In_ TsLayoutCode lcode,
|
|
_In_ TsViewCookie vcView)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnStatusChange(_In_ DWORD dwFlags)
|
|
{
|
|
HRESULT hr, hrSession;
|
|
|
|
TRACE("(%p) %x\n", this, dwFlags);
|
|
|
|
if (!m_pITextStoreACP)
|
|
{
|
|
FIXME("Context does not have a ITextStoreACP\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
hr = m_pITextStoreACP->RequestLock(TS_LF_READ, &hrSession);
|
|
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hrSession))
|
|
m_documentStatus.dwDynamicFlags = dwFlags;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnAttrsChange(
|
|
_In_ LONG acpStart,
|
|
_In_ LONG acpEnd,
|
|
_In_ ULONG cAttrs,
|
|
_In_ const TS_ATTRID *paAttrs)
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnLockGranted(_In_ DWORD dwLockFlags)
|
|
{
|
|
HRESULT hr;
|
|
EditCookie *cookie, *sinkcookie;
|
|
TfEditCookie ec;
|
|
struct list *cursor;
|
|
|
|
TRACE("(%p) %x\n", this, dwLockFlags);
|
|
|
|
if (!m_currentEditSession)
|
|
{
|
|
FIXME("OnLockGranted called for something other than an EditSession\n");
|
|
return S_OK;
|
|
}
|
|
|
|
cookie = (EditCookie *)HeapAlloc(GetProcessHeap(), 0, sizeof(EditCookie));
|
|
if (!cookie)
|
|
return E_OUTOFMEMORY;
|
|
|
|
sinkcookie = (EditCookie *)HeapAlloc(GetProcessHeap(), 0, sizeof(EditCookie));
|
|
if (!sinkcookie)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, cookie);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
cookie->lockType = dwLockFlags;
|
|
cookie->pOwningContext = this;
|
|
ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);
|
|
|
|
hr = m_currentEditSession->DoEditSession(ec);
|
|
|
|
if ((dwLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE)
|
|
{
|
|
ITfTextEditSink *sink;
|
|
TfEditCookie sc;
|
|
|
|
sinkcookie->lockType = TS_LF_READ;
|
|
sinkcookie->pOwningContext = this;
|
|
sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie);
|
|
|
|
/*TODO: implement ITfEditRecord */
|
|
SINK_FOR_EACH(cursor, &m_pTextEditSink, ITfTextEditSink, sink)
|
|
{
|
|
sink->OnEndEdit(static_cast<ITfContext *>(this), sc, NULL);
|
|
}
|
|
sinkcookie = (EditCookie *)remove_Cookie(sc);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, sinkcookie);
|
|
|
|
m_currentEditSession->Release();
|
|
m_currentEditSession = NULL;
|
|
|
|
/* Edit Cookie is only valid during the edit session */
|
|
cookie = (EditCookie *)remove_Cookie(ec);
|
|
HeapFree(GetProcessHeap(), 0, cookie);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnStartEditTransaction()
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::OnEndEditTransaction()
|
|
{
|
|
FIXME("STUB:(%p)\n", this);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::Serialize(
|
|
_In_ ITfProperty *prop,
|
|
_In_ ITfRange *range,
|
|
_Out_ TF_PERSISTENT_PROPERTY_HEADER_ACP *header,
|
|
_In_ IStream *stream)
|
|
{
|
|
FIXME("stub: %p %p %p %p %p\n", this, prop, range, header, stream);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::Unserialize(
|
|
_In_ ITfProperty *prop,
|
|
_In_ const TF_PERSISTENT_PROPERTY_HEADER_ACP *header,
|
|
_In_ IStream *stream,
|
|
_In_ ITfPersistentPropertyLoaderACP *loader)
|
|
{
|
|
FIXME("stub: %p %p %p %p %p\n", this, prop, header, stream, loader);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::ForceLoadProperty(_In_ ITfProperty *prop)
|
|
{
|
|
FIXME("stub: %p %p\n", this, prop);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CContext::CreateRange(
|
|
_In_ LONG start,
|
|
_In_ LONG end,
|
|
_Out_ ITfRangeACP **range)
|
|
{
|
|
FIXME("stub: %p %d %d %p\n", this, start, end, range);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CContext::CreateInstance(
|
|
TfClientId tidOwner,
|
|
IUnknown *punk,
|
|
ITfDocumentMgr *mgr,
|
|
ITfContext **ppOut,
|
|
TfEditCookie *pecTextStore)
|
|
{
|
|
CContext *This = new(cicNoThrow) CContext();
|
|
if (This == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
EditCookie *cookie = (EditCookie *)HeapAlloc(GetProcessHeap(), 0, sizeof(EditCookie));
|
|
if (cookie == NULL)
|
|
{
|
|
delete This;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
TRACE("(%p) %x %p %p %p\n", This, tidOwner, punk, ppOut, pecTextStore);
|
|
|
|
This->m_tidOwner = tidOwner;
|
|
This->m_manager = mgr;
|
|
|
|
CompartmentMgr_Constructor(static_cast<ITfContext *>(This), IID_IUnknown, (IUnknown **)&This->m_CompartmentMgr);
|
|
|
|
cookie->lockType = TF_ES_READ;
|
|
cookie->pOwningContext = This;
|
|
|
|
if (punk)
|
|
{
|
|
punk->QueryInterface(IID_ITextStoreACP, (LPVOID*)&This->m_pITextStoreACP);
|
|
punk->QueryInterface(IID_ITfContextOwnerCompositionSink, (LPVOID*)&This->m_pITfContextOwnerCompositionSink);
|
|
|
|
if (!This->m_pITextStoreACP && !This->m_pITfContextOwnerCompositionSink)
|
|
FIXME("Unhandled pUnk\n");
|
|
}
|
|
|
|
This->m_defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);
|
|
*pecTextStore = This->m_defaultCookie;
|
|
|
|
list_init(&This->m_pContextKeyEventSink);
|
|
list_init(&This->m_pEditTransactionSink);
|
|
list_init(&This->m_pStatusSink);
|
|
list_init(&This->m_pTextEditSink);
|
|
list_init(&This->m_pTextLayoutSink);
|
|
|
|
*ppOut = static_cast<ITfContext *>(This);
|
|
TRACE("returning %p\n", *ppOut);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CContext::Initialize(ITfDocumentMgr *manager)
|
|
{
|
|
if (m_pITextStoreACP)
|
|
{
|
|
m_pITextStoreACP->AdviseSink(IID_ITextStoreACPSink,
|
|
static_cast<ITextStoreACPSink *>(this),
|
|
TS_AS_ALL_SINKS);
|
|
}
|
|
m_connected = TRUE;
|
|
m_manager = manager;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CContext::Uninitialize()
|
|
{
|
|
if (m_pITextStoreACP)
|
|
m_pITextStoreACP->UnadviseSink(static_cast<ITextStoreACPSink *>(this));
|
|
m_connected = FALSE;
|
|
m_manager = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
EXTERN_C
|
|
HRESULT
|
|
Context_Constructor(
|
|
TfClientId tidOwner,
|
|
IUnknown *punk,
|
|
ITfDocumentMgr *mgr,
|
|
ITfContext **ppOut,
|
|
TfEditCookie *pecTextStore)
|
|
{
|
|
return CContext::CreateInstance(tidOwner, punk, mgr, ppOut, pecTextStore);
|
|
}
|
|
|
|
EXTERN_C
|
|
HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager)
|
|
{
|
|
CContext *This = static_cast<CContext *>(iface);
|
|
return This->Initialize(manager);
|
|
}
|
|
|
|
EXTERN_C
|
|
HRESULT Context_Uninitialize(ITfContext *iface)
|
|
{
|
|
CContext *This = static_cast<CContext *>(iface);
|
|
return This->Uninitialize();
|
|
}
|