From 93181db68b34b203d10ab82f8ac7e0fad61c4dbe Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Sat, 5 Jul 2025 20:09:00 +0900 Subject: [PATCH] [MSCTF] Make ITfContext C++ (#8224) Implementing missing features... JIRA issue: CORE-19361 - Delete context.c and add context.cpp. - Make ITfContext implementation C++. --- base/ctf/msctf/CMakeLists.txt | 2 +- base/ctf/msctf/context.c | 1130 --------------------------------- base/ctf/msctf/context.cpp | 1012 +++++++++++++++++++++++++++++ 3 files changed, 1013 insertions(+), 1131 deletions(-) delete mode 100644 base/ctf/msctf/context.c create mode 100644 base/ctf/msctf/context.cpp diff --git a/base/ctf/msctf/CMakeLists.txt b/base/ctf/msctf/CMakeLists.txt index 655eac1916a..82c0266ff56 100644 --- a/base/ctf/msctf/CMakeLists.txt +++ b/base/ctf/msctf/CMakeLists.txt @@ -5,7 +5,6 @@ add_definitions(-D_WIN32_WINNT=0x600) spec2def(msctf.dll msctf.spec ADD_IMPORTLIB) list(APPEND SOURCE - context.c inputprocessor.c msctf.c threadmgr.c @@ -14,6 +13,7 @@ list(APPEND SOURCE list(APPEND PCH_SKIP_SOURCE categorymgr.cpp + context.cpp compartmentmgr.cpp displayattributemgr.cpp documentmgr.cpp diff --git a/base/ctf/msctf/context.c b/base/ctf/msctf/context.c deleted file mode 100644 index 63f2bf5455d..00000000000 --- a/base/ctf/msctf/context.c +++ /dev/null @@ -1,1130 +0,0 @@ -/* - * ITfContext 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 "olectl.h" - -#include "msctf.h" -#include "msctf_internal.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msctf); - -typedef struct tagContext { - ITfContext ITfContext_iface; - ITfSource ITfSource_iface; - /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */ - ITfContextOwnerCompositionServices ITfContextOwnerCompositionServices_iface; - /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */ - ITfInsertAtSelection ITfInsertAtSelection_iface; - /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */ - /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */ - ITfSourceSingle ITfSourceSingle_iface; - ITextStoreACPSink ITextStoreACPSink_iface; - ITextStoreACPServices ITextStoreACPServices_iface; - LONG refCount; - BOOL connected; - - /* Aggregation */ - ITfCompartmentMgr *CompartmentMgr; - - TfClientId tidOwner; - TfEditCookie defaultCookie; - TS_STATUS documentStatus; - ITfDocumentMgr *manager; - - ITextStoreACP *pITextStoreACP; - ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink; - - ITfEditSession* currentEditSession; - - /* kept as separate lists to reduce unnecessary iterations */ - struct list pContextKeyEventSink; - struct list pEditTransactionSink; - struct list pStatusSink; - struct list pTextEditSink; - struct list pTextLayoutSink; - -} Context; - -typedef struct tagEditCookie { - DWORD lockType; - Context *pOwningContext; -} EditCookie; - -static inline Context *impl_from_ITfContext(ITfContext *iface) -{ - return CONTAINING_RECORD(iface, Context, ITfContext_iface); -} - -static inline Context *impl_from_ITfSource(ITfSource *iface) -{ - return CONTAINING_RECORD(iface, Context, ITfSource_iface); -} - -static inline Context *impl_from_ITfContextOwnerCompositionServices(ITfContextOwnerCompositionServices *iface) -{ - return CONTAINING_RECORD(iface, Context, ITfContextOwnerCompositionServices_iface); -} - -static inline Context *impl_from_ITfInsertAtSelection(ITfInsertAtSelection *iface) -{ - return CONTAINING_RECORD(iface, Context, ITfInsertAtSelection_iface); -} - -static inline Context *impl_from_ITfSourceSingle(ITfSourceSingle* iface) -{ - return CONTAINING_RECORD(iface, Context, ITfSourceSingle_iface); -} - -static inline Context *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface) -{ - return CONTAINING_RECORD(iface, Context, ITextStoreACPSink_iface); -} - -static inline Context *impl_from_ITextStoreACPServices(ITextStoreACPServices *iface) -{ - return CONTAINING_RECORD(iface, Context, ITextStoreACPServices_iface); -} - -static void Context_Destructor(Context *This) -{ - EditCookie *cookie; - TRACE("destroying %p\n", This); - - if (This->pITextStoreACP) - ITextStoreACP_Release(This->pITextStoreACP); - - if (This->pITfContextOwnerCompositionSink) - ITfContextOwnerCompositionSink_Release(This->pITfContextOwnerCompositionSink); - - if (This->defaultCookie) - { - cookie = remove_Cookie(This->defaultCookie); - HeapFree(GetProcessHeap(),0,cookie); - This->defaultCookie = 0; - } - - free_sinks(&This->pContextKeyEventSink); - free_sinks(&This->pEditTransactionSink); - free_sinks(&This->pStatusSink); - free_sinks(&This->pTextEditSink); - free_sinks(&This->pTextLayoutSink); - - CompartmentMgr_Destructor(This->CompartmentMgr); - HeapFree(GetProcessHeap(),0,This); -} - -static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut) -{ - Context *This = impl_from_ITfContext(iface); - *ppvOut = NULL; - - if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext)) - { - *ppvOut = &This->ITfContext_iface; - } - else if (IsEqualIID(iid, &IID_ITfSource)) - { - *ppvOut = &This->ITfSource_iface; - } - else if (IsEqualIID(iid, &IID_ITfContextOwnerCompositionServices)) - { - *ppvOut = &This->ITfContextOwnerCompositionServices_iface; - } - else if (IsEqualIID(iid, &IID_ITfInsertAtSelection)) - { - *ppvOut = &This->ITfInsertAtSelection_iface; - } - else if (IsEqualIID(iid, &IID_ITfCompartmentMgr)) - { - *ppvOut = This->CompartmentMgr; - } - else if (IsEqualIID(iid, &IID_ITfSourceSingle)) - { - *ppvOut = &This->ITfSourceSingle_iface; - } - - if (*ppvOut) - { - ITfContext_AddRef(iface); - return S_OK; - } - - WARN("unsupported interface: %s\n", debugstr_guid(iid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI Context_AddRef(ITfContext *iface) -{ - Context *This = impl_from_ITfContext(iface); - return InterlockedIncrement(&This->refCount); -} - -static ULONG WINAPI Context_Release(ITfContext *iface) -{ - Context *This = impl_from_ITfContext(iface); - ULONG ret; - - ret = InterlockedDecrement(&This->refCount); - if (ret == 0) - Context_Destructor(This); - return ret; -} - -/***************************************************** - * ITfContext functions - *****************************************************/ -static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface, - TfClientId tid, ITfEditSession *pes, DWORD dwFlags, - HRESULT *phrSession) -{ - Context *This = impl_from_ITfContext(iface); - 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 (!This->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 (!This->documentStatus.dwDynamicFlags) - ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus); - - if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY)) - { - *phrSession = TS_E_READONLY; - return S_OK; - } - - if (FAILED (ITfEditSession_QueryInterface(pes, &IID_ITfEditSession, (LPVOID*)&This->currentEditSession))) - { - *phrSession = E_FAIL; - return E_INVALIDARG; - } - - hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession); - - return hr; -} - -static HRESULT WINAPI Context_InWriteSession (ITfContext *iface, - TfClientId tid, - BOOL *pfWriteSession) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_GetSelection (ITfContext *iface, - TfEditCookie ec, ULONG ulIndex, ULONG ulCount, - TF_SELECTION *pSelection, ULONG *pcFetched) -{ - Context *This = impl_from_ITfContext(iface); - EditCookie *cookie; - ULONG count, i; - ULONG totalFetched = 0; - HRESULT hr = S_OK; - - if (!pSelection || !pcFetched) - return E_INVALIDARG; - - *pcFetched = 0; - - if (!This->connected) - return TF_E_DISCONNECTED; - - if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) - return TF_E_NOLOCK; - - if (!This->pITextStoreACP) - { - FIXME("Context does not have a ITextStoreACP\n"); - return E_NOTIMPL; - } - - cookie = get_Cookie_data(ec); - - if (ulIndex == TF_DEFAULT_SELECTION) - count = 1; - else - count = ulCount; - - for (i = 0; i < count; i++) - { - DWORD fetched; - TS_SELECTION_ACP acps; - - hr = ITextStoreACP_GetSelection(This->pITextStoreACP, ulIndex + i, - 1, &acps, &fetched); - - if (hr == TS_E_NOLOCK) - return TF_E_NOLOCK; - else if (SUCCEEDED(hr)) - { - pSelection[totalFetched].style.ase = acps.style.ase; - pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar; - Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range); - totalFetched ++; - } - else - break; - } - - *pcFetched = totalFetched; - - return hr; -} - -static HRESULT WINAPI Context_SetSelection (ITfContext *iface, - TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection) -{ - Context *This = impl_from_ITfContext(iface); - TS_SELECTION_ACP *acp; - ULONG i; - HRESULT hr; - - TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection); - - if (!This->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 = 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 = ITextStoreACP_SetSelection(This->pITextStoreACP, ulCount, acp); - - HeapFree(GetProcessHeap(), 0, acp); - - return hr; -} - -static HRESULT WINAPI Context_GetStart (ITfContext *iface, - TfEditCookie ec, ITfRange **ppStart) -{ - Context *This = impl_from_ITfContext(iface); - EditCookie *cookie; - TRACE("(%p) %i %p\n",This,ec,ppStart); - - if (!ppStart) - return E_INVALIDARG; - - *ppStart = NULL; - - if (!This->connected) - return TF_E_DISCONNECTED; - - if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) - return TF_E_NOLOCK; - - cookie = get_Cookie_data(ec); - return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, 0, 0, ppStart); -} - -static HRESULT WINAPI Context_GetEnd (ITfContext *iface, - TfEditCookie ec, ITfRange **ppEnd) -{ - Context *This = impl_from_ITfContext(iface); - EditCookie *cookie; - LONG end; - TRACE("(%p) %i %p\n",This,ec,ppEnd); - - if (!ppEnd) - return E_INVALIDARG; - - *ppEnd = NULL; - - if (!This->connected) - return TF_E_DISCONNECTED; - - if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) - return TF_E_NOLOCK; - - if (!This->pITextStoreACP) - { - FIXME("Context does not have a ITextStoreACP\n"); - return E_NOTIMPL; - } - - cookie = get_Cookie_data(ec); - ITextStoreACP_GetEndACP(This->pITextStoreACP,&end); - - return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, end, end, ppEnd); -} - -static HRESULT WINAPI Context_GetActiveView (ITfContext *iface, - ITfContextView **ppView) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_EnumViews (ITfContext *iface, - IEnumTfContextViews **ppEnum) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_GetStatus (ITfContext *iface, - TF_STATUS *pdcs) -{ - Context *This = impl_from_ITfContext(iface); - TRACE("(%p) %p\n",This,pdcs); - - if (!This->connected) - return TF_E_DISCONNECTED; - - if (!pdcs) - return E_INVALIDARG; - - if (!This->pITextStoreACP) - { - FIXME("Context does not have a ITextStoreACP\n"); - return E_NOTIMPL; - } - - ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus); - - *pdcs = This->documentStatus; - - return S_OK; -} - -static HRESULT WINAPI Context_GetProperty (ITfContext *iface, - REFGUID guidProp, ITfProperty **ppProp) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface, - REFGUID guidProp, ITfReadOnlyProperty **ppProp) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_TrackProperties (ITfContext *iface, - const GUID **prgProp, ULONG cProp, const GUID **prgAppProp, - ULONG cAppProp, ITfReadOnlyProperty **ppProperty) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_EnumProperties (ITfContext *iface, - IEnumTfProperties **ppEnum) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface, - ITfDocumentMgr **ppDm) -{ - Context *This = impl_from_ITfContext(iface); - TRACE("(%p) %p\n",This,ppDm); - - if (!ppDm) - return E_INVALIDARG; - - *ppDm = This->manager; - if (!This->manager) - return S_FALSE; - - ITfDocumentMgr_AddRef(This->manager); - - return S_OK; -} - -static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface, - TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup) -{ - Context *This = impl_from_ITfContext(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static const ITfContextVtbl ContextVtbl = -{ - Context_QueryInterface, - Context_AddRef, - Context_Release, - Context_RequestEditSession, - Context_InWriteSession, - Context_GetSelection, - Context_SetSelection, - Context_GetStart, - Context_GetEnd, - Context_GetActiveView, - Context_EnumViews, - Context_GetStatus, - Context_GetProperty, - Context_GetAppProperty, - Context_TrackProperties, - Context_EnumProperties, - Context_GetDocumentMgr, - Context_CreateRangeBackup -}; - -/***************************************************** - * ITfSource functions - *****************************************************/ -static HRESULT WINAPI ContextSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) -{ - Context *This = impl_from_ITfSource(iface); - return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); -} - -static ULONG WINAPI ContextSource_AddRef(ITfSource *iface) -{ - Context *This = impl_from_ITfSource(iface); - return ITfContext_AddRef(&This->ITfContext_iface); -} - -static ULONG WINAPI ContextSource_Release(ITfSource *iface) -{ - Context *This = impl_from_ITfSource(iface); - return ITfContext_Release(&This->ITfContext_iface); -} - -static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface, - REFIID riid, IUnknown *punk, DWORD *pdwCookie) -{ - Context *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_ITfTextEditSink)) - return advise_sink(&This->pTextEditSink, &IID_ITfTextEditSink, COOKIE_MAGIC_CONTEXTSINK, punk, pdwCookie); - - FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); - return E_NOTIMPL; -} - -static HRESULT WINAPI ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) -{ - Context *This = impl_from_ITfSource(iface); - - TRACE("(%p) %x\n",This,pdwCookie); - - if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK) - return E_INVALIDARG; - - return unadvise_sink(pdwCookie); -} - -static const ITfSourceVtbl ContextSourceVtbl = -{ - ContextSource_QueryInterface, - ContextSource_AddRef, - ContextSource_Release, - ContextSource_AdviseSink, - ContextSource_UnadviseSink -}; - -/***************************************************** - * ITfContextOwnerCompositionServices functions - *****************************************************/ -static HRESULT WINAPI ContextOwnerCompositionServices_QueryInterface(ITfContextOwnerCompositionServices *iface, - REFIID iid, LPVOID *ppvOut) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); -} - -static ULONG WINAPI ContextOwnerCompositionServices_AddRef(ITfContextOwnerCompositionServices *iface) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - return ITfContext_AddRef(&This->ITfContext_iface); -} - -static ULONG WINAPI ContextOwnerCompositionServices_Release(ITfContextOwnerCompositionServices *iface) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - return ITfContext_Release(&This->ITfContext_iface); -} - -static HRESULT WINAPI ContextOwnerCompositionServices_StartComposition(ITfContextOwnerCompositionServices *iface, - TfEditCookie ecWrite, ITfRange *pCompositionRange, ITfCompositionSink *pSink, ITfComposition **ppComposition) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - FIXME("STUB:(%p) %#x %p %p %p\n", This, ecWrite, pCompositionRange, pSink, ppComposition); - return E_NOTIMPL; -} - -static HRESULT WINAPI ContextOwnerCompositionServices_EnumCompositions(ITfContextOwnerCompositionServices *iface, - IEnumITfCompositionView **ppEnum) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - FIXME("STUB:(%p) %p\n", This, ppEnum); - return E_NOTIMPL; -} - -static HRESULT WINAPI ContextOwnerCompositionServices_FindComposition(ITfContextOwnerCompositionServices *iface, - TfEditCookie ecRead, ITfRange *pTestRange, IEnumITfCompositionView **ppEnum) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - FIXME("STUB:(%p) %#x %p %p\n", This, ecRead, pTestRange, ppEnum); - return E_NOTIMPL; -} - -static HRESULT WINAPI ContextOwnerCompositionServices_TakeOwnership(ITfContextOwnerCompositionServices *iface, - TfEditCookie ecWrite, ITfCompositionView *pComposition, ITfCompositionSink *pSink, ITfComposition **ppComposition) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - FIXME("STUB:(%p) %#x %p %p %p\n", This, ecWrite, pComposition, pSink, ppComposition); - return E_NOTIMPL; -} - -static HRESULT WINAPI ContextOwnerCompositionServices_TerminateComposition(ITfContextOwnerCompositionServices *iface, - ITfCompositionView *pComposition) -{ - Context *This = impl_from_ITfContextOwnerCompositionServices(iface); - FIXME("STUB:(%p) %p\n", This, pComposition); - return E_NOTIMPL; -} - -static const ITfContextOwnerCompositionServicesVtbl ContextOwnerCompositionServicesVtbl = -{ - ContextOwnerCompositionServices_QueryInterface, - ContextOwnerCompositionServices_AddRef, - ContextOwnerCompositionServices_Release, - ContextOwnerCompositionServices_StartComposition, - ContextOwnerCompositionServices_EnumCompositions, - ContextOwnerCompositionServices_FindComposition, - ContextOwnerCompositionServices_TakeOwnership, - ContextOwnerCompositionServices_TerminateComposition -}; - -/***************************************************** - * ITfInsertAtSelection functions - *****************************************************/ -static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut) -{ - Context *This = impl_from_ITfInsertAtSelection(iface); - return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); -} - -static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface) -{ - Context *This = impl_from_ITfInsertAtSelection(iface); - return ITfContext_AddRef(&This->ITfContext_iface); -} - -static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface) -{ - Context *This = impl_from_ITfInsertAtSelection(iface); - return ITfContext_Release(&This->ITfContext_iface); -} - -static HRESULT WINAPI InsertAtSelection_InsertTextAtSelection( - ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags, - const WCHAR *pchText, LONG cch, ITfRange **ppRange) -{ - Context *This = impl_from_ITfInsertAtSelection(iface); - 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 (!This->connected) - return TF_E_DISCONNECTED; - - if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE) - return TF_E_NOLOCK; - - cookie = get_Cookie_data(ec); - - if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE ) - return TS_E_READONLY; - - if (!This->pITextStoreACP) - { - FIXME("Context does not have a ITextStoreACP\n"); - return E_NOTIMPL; - } - - hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change); - if (SUCCEEDED(hr)) - Range_Constructor(&This->ITfContext_iface, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange); - - return hr; -} - -static HRESULT WINAPI InsertAtSelection_InsertEmbeddedAtSelection( - ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags, - IDataObject *pDataObject, ITfRange **ppRange) -{ - Context *This = impl_from_ITfInsertAtSelection(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static const ITfInsertAtSelectionVtbl InsertAtSelectionVtbl = -{ - InsertAtSelection_QueryInterface, - InsertAtSelection_AddRef, - InsertAtSelection_Release, - InsertAtSelection_InsertTextAtSelection, - InsertAtSelection_InsertEmbeddedAtSelection, -}; - -/***************************************************** - * ITfSourceSingle functions - *****************************************************/ -static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut) -{ - Context *This = impl_from_ITfSourceSingle(iface); - return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut); -} - -static ULONG WINAPI SourceSingle_AddRef(ITfSourceSingle *iface) -{ - Context *This = impl_from_ITfSourceSingle(iface); - return ITfContext_AddRef(&This->ITfContext_iface); -} - -static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface) -{ - Context *This = impl_from_ITfSourceSingle(iface); - return ITfContext_Release(&This->ITfContext_iface); -} - -static HRESULT WINAPI SourceSingle_AdviseSingleSink( ITfSourceSingle *iface, - TfClientId tid, REFIID riid, IUnknown *punk) -{ - Context *This = impl_from_ITfSourceSingle(iface); - FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk); - return E_NOTIMPL; -} - -static HRESULT WINAPI SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface, - TfClientId tid, REFIID riid) -{ - Context *This = impl_from_ITfSourceSingle(iface); - FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid)); - return E_NOTIMPL; -} - -static const ITfSourceSingleVtbl ContextSourceSingleVtbl = -{ - SourceSingle_QueryInterface, - SourceSingle_AddRef, - SourceSingle_Release, - SourceSingle_AdviseSingleSink, - SourceSingle_UnadviseSingleSink, -}; - -/************************************************************************** - * ITextStoreACPSink - **************************************************************************/ - -static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - - *ppvOut = NULL; - - if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink)) - { - *ppvOut = &This->ITextStoreACPSink_iface; - } - else if (IsEqualIID(iid, &IID_ITextStoreACPServices)) - *ppvOut = &This->ITextStoreACPServices_iface; - - if (*ppvOut) - { - ITextStoreACPSink_AddRef(iface); - return S_OK; - } - - WARN("unsupported interface: %s\n", debugstr_guid(iid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - return ITfContext_AddRef(&This->ITfContext_iface); -} - -static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - return ITfContext_Release(&This->ITfContext_iface); -} - -/***************************************************** - * ITextStoreACPSink functions - *****************************************************/ - -static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface, - DWORD dwFlags, const TS_TEXTCHANGE *pChange) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - FIXME("STUB:(%p)\n",This); - return S_OK; -} - -static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - FIXME("STUB:(%p)\n",This); - return S_OK; -} - -static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface, - TsLayoutCode lcode, TsViewCookie vcView) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - FIXME("STUB:(%p)\n",This); - return S_OK; -} - -static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface, - DWORD dwFlags) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - HRESULT hr, hrSession; - - TRACE("(%p) %x\n",This, dwFlags); - - if (!This->pITextStoreACP) - { - FIXME("Context does not have a ITextStoreACP\n"); - return E_NOTIMPL; - } - - hr = ITextStoreACP_RequestLock(This->pITextStoreACP, TS_LF_READ, &hrSession); - - if(SUCCEEDED(hr) && SUCCEEDED(hrSession)) - This->documentStatus.dwDynamicFlags = dwFlags; - - return S_OK; -} - -static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface, - LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface, - DWORD dwLockFlags) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - HRESULT hr; - EditCookie *cookie,*sinkcookie; - TfEditCookie ec; - struct list *cursor; - - TRACE("(%p) %x\n",This, dwLockFlags); - - if (!This->currentEditSession) - { - FIXME("OnLockGranted called for something other than an EditSession\n"); - return S_OK; - } - - cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie)); - if (!cookie) - return E_OUTOFMEMORY; - - sinkcookie = 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 = ITfEditSession_DoEditSession(This->currentEditSession, 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, &This->pTextEditSink, ITfTextEditSink, sink) - { - ITfTextEditSink_OnEndEdit(sink, &This->ITfContext_iface, sc, NULL); - } - sinkcookie = remove_Cookie(sc); - } - HeapFree(GetProcessHeap(),0,sinkcookie); - - ITfEditSession_Release(This->currentEditSession); - This->currentEditSession = NULL; - - /* Edit Cookie is only valid during the edit session */ - cookie = remove_Cookie(ec); - HeapFree(GetProcessHeap(),0,cookie); - - return hr; -} - -static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface) -{ - Context *This = impl_from_ITextStoreACPSink(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; -} - -static const ITextStoreACPSinkVtbl TextStoreACPSinkVtbl = -{ - TextStoreACPSink_QueryInterface, - TextStoreACPSink_AddRef, - TextStoreACPSink_Release, - TextStoreACPSink_OnTextChange, - TextStoreACPSink_OnSelectionChange, - TextStoreACPSink_OnLayoutChange, - TextStoreACPSink_OnStatusChange, - TextStoreACPSink_OnAttrsChange, - TextStoreACPSink_OnLockGranted, - TextStoreACPSink_OnStartEditTransaction, - TextStoreACPSink_OnEndEditTransaction -}; - -static HRESULT WINAPI TextStoreACPServices_QueryInterface(ITextStoreACPServices *iface, REFIID riid, void **obj) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - return ITextStoreACPSink_QueryInterface(&This->ITextStoreACPSink_iface, riid, obj); -} - -static ULONG WINAPI TextStoreACPServices_AddRef(ITextStoreACPServices *iface) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - return ITextStoreACPSink_AddRef(&This->ITextStoreACPSink_iface); -} - -static ULONG WINAPI TextStoreACPServices_Release(ITextStoreACPServices *iface) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - return ITextStoreACPSink_Release(&This->ITextStoreACPSink_iface); -} - -static HRESULT WINAPI TextStoreACPServices_Serialize(ITextStoreACPServices *iface, ITfProperty *prop, ITfRange *range, - TF_PERSISTENT_PROPERTY_HEADER_ACP *header, IStream *stream) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - - FIXME("stub: %p %p %p %p %p\n", This, prop, range, header, stream); - - return E_NOTIMPL; -} - -static HRESULT WINAPI TextStoreACPServices_Unserialize(ITextStoreACPServices *iface, ITfProperty *prop, - const TF_PERSISTENT_PROPERTY_HEADER_ACP *header, IStream *stream, ITfPersistentPropertyLoaderACP *loader) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - - FIXME("stub: %p %p %p %p %p\n", This, prop, header, stream, loader); - - return E_NOTIMPL; -} - -static HRESULT WINAPI TextStoreACPServices_ForceLoadProperty(ITextStoreACPServices *iface, ITfProperty *prop) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - - FIXME("stub: %p %p\n", This, prop); - - return E_NOTIMPL; -} - -static HRESULT WINAPI TextStoreACPServices_CreateRange(ITextStoreACPServices *iface, - LONG start, LONG end, ITfRangeACP **range) -{ - Context *This = impl_from_ITextStoreACPServices(iface); - - FIXME("stub: %p %d %d %p\n", This, start, end, range); - - return S_OK; -} - -static const ITextStoreACPServicesVtbl TextStoreACPServicesVtbl = -{ - TextStoreACPServices_QueryInterface, - TextStoreACPServices_AddRef, - TextStoreACPServices_Release, - TextStoreACPServices_Serialize, - TextStoreACPServices_Unserialize, - TextStoreACPServices_ForceLoadProperty, - TextStoreACPServices_CreateRange -}; - -HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore) -{ - Context *This; - EditCookie *cookie; - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context)); - if (This == NULL) - return E_OUTOFMEMORY; - - cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie)); - if (cookie == NULL) - { - HeapFree(GetProcessHeap(),0,This); - return E_OUTOFMEMORY; - } - - TRACE("(%p) %x %p %p %p\n",This, tidOwner, punk, ppOut, pecTextStore); - - This->ITfContext_iface.lpVtbl= &ContextVtbl; - This->ITfSource_iface.lpVtbl = &ContextSourceVtbl; - This->ITfContextOwnerCompositionServices_iface.lpVtbl = &ContextOwnerCompositionServicesVtbl; - This->ITfInsertAtSelection_iface.lpVtbl = &InsertAtSelectionVtbl; - This->ITfSourceSingle_iface.lpVtbl = &ContextSourceSingleVtbl; - This->ITextStoreACPSink_iface.lpVtbl = &TextStoreACPSinkVtbl; - This->ITextStoreACPServices_iface.lpVtbl = &TextStoreACPServicesVtbl; - This->refCount = 1; - This->tidOwner = tidOwner; - This->connected = FALSE; - This->manager = mgr; - - CompartmentMgr_Constructor((IUnknown*)&This->ITfContext_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); - - cookie->lockType = TF_ES_READ; - cookie->pOwningContext = This; - - if (punk) - { - IUnknown_QueryInterface(punk, &IID_ITextStoreACP, - (LPVOID*)&This->pITextStoreACP); - - IUnknown_QueryInterface(punk, &IID_ITfContextOwnerCompositionSink, - (LPVOID*)&This->pITfContextOwnerCompositionSink); - - if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink) - FIXME("Unhandled pUnk\n"); - } - - This->defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE,cookie); - *pecTextStore = This->defaultCookie; - - list_init(&This->pContextKeyEventSink); - list_init(&This->pEditTransactionSink); - list_init(&This->pStatusSink); - list_init(&This->pTextEditSink); - list_init(&This->pTextLayoutSink); - - *ppOut = &This->ITfContext_iface; - TRACE("returning %p\n", *ppOut); - - return S_OK; -} - -HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager) -{ - Context *This = impl_from_ITfContext(iface); - - if (This->pITextStoreACP) - ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink, - (IUnknown*)&This->ITextStoreACPSink_iface, TS_AS_ALL_SINKS); - This->connected = TRUE; - This->manager = manager; - return S_OK; -} - -HRESULT Context_Uninitialize(ITfContext *iface) -{ - Context *This = impl_from_ITfContext(iface); - - if (This->pITextStoreACP) - ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)&This->ITextStoreACPSink_iface); - This->connected = FALSE; - This->manager = NULL; - return S_OK; -} diff --git a/base/ctf/msctf/context.cpp b/base/ctf/msctf/context.cpp new file mode 100644 index 00000000000..9f2ea2350e8 --- /dev/null +++ b/base/ctf/msctf/context.cpp @@ -0,0 +1,1012 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Cicero +#include +#include +#include + +#include "msctf_internal.h" + +#include +WINE_DEFAULT_DEBUG_CHANNEL(msctf); + +static inline bool cicIsNullPtr(LPCVOID ptr) +{ + return !ptr; +} + +//////////////////////////////////////////////////////////////////////////// + +class CContext + : public ITfContext + , public ITfSource + , public ITfContextOwnerCompositionServices + , public ITfInsertAtSelection + , 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(this); + else if (riid == IID_ITfSource) + *ppvObj = static_cast(this); + else if (riid == IID_ITfContextOwnerCompositionServices) + *ppvObj = static_cast(this); + else if (riid == IID_ITfInsertAtSelection) + *ppvObj = static_cast(this); + else if (riid == IID_ITfCompartmentMgr) + *ppvObj = m_CompartmentMgr; + else if (riid == IID_ITfSourceSingle) + *ppvObj = static_cast(this); + else if (riid == IID_ITextStoreACPSink) + *ppvObj = static_cast(this); + else if (riid == IID_ITextStoreACPServices) + *ppvObj = static_cast(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 (SUCCEEDED(hr)) + { + 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++; + } + else + break; + } + + *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(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(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(This); + TRACE("returning %p\n", *ppOut); + + return S_OK; +} + +HRESULT CContext::Initialize(ITfDocumentMgr *manager) +{ + if (m_pITextStoreACP) + { + m_pITextStoreACP->AdviseSink(IID_ITextStoreACPSink, + static_cast(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(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(iface); + return This->Initialize(manager); +} + +EXTERN_C +HRESULT Context_Uninitialize(ITfContext *iface) +{ + CContext *This = static_cast(iface); + return This->Uninitialize(); +}