[MSCTF] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / msctf / context.c
index c013cf9..54052f6 100644 (file)
 #include "olectl.h"
 
 #include "wine/unicode.h"
-#include "wine/list.h"
 
 #include "msctf.h"
 #include "msctf_internal.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
 
-typedef struct tagContextSink {
-    struct list         entry;
-    union {
-        /* Context Sinks */
-        IUnknown            *pIUnknown;
-        /* ITfContextKeyEventSink  *pITfContextKeyEventSink; */
-        /* ITfEditTransactionSink  *pITfEditTransactionSink; */
-        /* ITfStatusSink           *pITfStatusSink; */
-        ITfTextEditSink     *pITfTextEditSink;
-        /* ITfTextLayoutSink       *pITfTextLayoutSink; */
-    } interfaces;
-} ContextSink;
-
 typedef struct tagContext {
-    const ITfContextVtbl *ContextVtbl;
-    const ITfSourceVtbl *SourceVtbl;
+    ITfContext ITfContext_iface;
+    ITfSource ITfSource_iface;
     /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */
     /* const ITfContextOwnerCompositionServicesVtbl *ContextOwnerCompositionServicesVtbl; */
     /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */
-    const ITfInsertAtSelectionVtbl *InsertAtSelectionVtbl;
+    ITfInsertAtSelection ITfInsertAtSelection_iface;
     /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
     /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
-    const ITfSourceSingleVtbl *SourceSingleVtbl;
+    ITfSourceSingle ITfSourceSingle_iface;
+    ITextStoreACPSink ITextStoreACPSink_iface;
+    ITextStoreACPServices ITextStoreACPServices_iface;
     LONG refCount;
     BOOL connected;
 
@@ -79,7 +67,6 @@ typedef struct tagContext {
     ITextStoreACP   *pITextStoreACP;
     ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
 
-    ITextStoreACPSink *pITextStoreACPSink;
     ITfEditSession* currentEditSession;
 
     /* kept as separate lists to reduce unnecessary iterations */
@@ -96,55 +83,46 @@ typedef struct tagEditCookie {
     Context *pOwningContext;
 } EditCookie;
 
-typedef struct tagTextStoreACPSink {
-    const ITextStoreACPSinkVtbl *TextStoreACPSinkVtbl;
-    /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
-    LONG refCount;
-
-    Context *pContext;
-} TextStoreACPSink;
-
+static inline Context *impl_from_ITfContext(ITfContext *iface)
+{
+    return CONTAINING_RECORD(iface, Context, ITfContext_iface);
+}
 
-static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);
+static inline Context *impl_from_ITfSource(ITfSource *iface)
+{
+    return CONTAINING_RECORD(iface, Context, ITfSource_iface);
+}
 
-static inline Context *impl_from_ITfSourceVtbl(ITfSource *iface)
+static inline Context *impl_from_ITfInsertAtSelection(ITfInsertAtSelection *iface)
 {
-    return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceVtbl));
+    return CONTAINING_RECORD(iface, Context, ITfInsertAtSelection_iface);
 }
 
-static inline Context *impl_from_ITfInsertAtSelectionVtbl(ITfInsertAtSelection*iface)
+static inline Context *impl_from_ITfSourceSingle(ITfSourceSingle* iface)
 {
-    return (Context *)((char *)iface - FIELD_OFFSET(Context,InsertAtSelectionVtbl));
+    return CONTAINING_RECORD(iface, Context, ITfSourceSingle_iface);
 }
 
-static inline Context *impl_from_ITfSourceSingleVtbl(ITfSourceSingle* iface)
+static inline Context *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface)
 {
-    return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceSingleVtbl));
+    return CONTAINING_RECORD(iface, Context, ITextStoreACPSink_iface);
 }
 
-static void free_sink(ContextSink *sink)
+static inline Context *impl_from_ITextStoreACPServices(ITextStoreACPServices *iface)
 {
-        IUnknown_Release(sink->interfaces.pIUnknown);
-        HeapFree(GetProcessHeap(),0,sink);
+    return CONTAINING_RECORD(iface, Context, ITextStoreACPServices_iface);
 }
 
 static void Context_Destructor(Context *This)
 {
-    struct list *cursor, *cursor2;
     EditCookie *cookie;
     TRACE("destroying %p\n", This);
 
-    if (This->pITextStoreACPSink)
-    {
-        ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
-        ITextStoreACPSink_Release(This->pITextStoreACPSink);
-    }
-
     if (This->pITextStoreACP)
-        ITextStoreACPSink_Release(This->pITextStoreACP);
+        ITextStoreACP_Release(This->pITextStoreACP);
 
     if (This->pITfContextOwnerCompositionSink)
-        ITextStoreACPSink_Release(This->pITfContextOwnerCompositionSink);
+        ITfContextOwnerCompositionSink_Release(This->pITfContextOwnerCompositionSink);
 
     if (This->defaultCookie)
     {
@@ -153,36 +131,11 @@ static void Context_Destructor(Context *This)
         This->defaultCookie = 0;
     }
 
-    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pContextKeyEventSink)
-    {
-        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
-        list_remove(cursor);
-        free_sink(sink);
-    }
-    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pEditTransactionSink)
-    {
-        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
-        list_remove(cursor);
-        free_sink(sink);
-    }
-    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pStatusSink)
-    {
-        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
-        list_remove(cursor);
-        free_sink(sink);
-    }
-    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextEditSink)
-    {
-        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
-        list_remove(cursor);
-        free_sink(sink);
-    }
-    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextLayoutSink)
-    {
-        ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
-        list_remove(cursor);
-        free_sink(sink);
-    }
+    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);
@@ -190,20 +143,20 @@ static void Context_Destructor(Context *This)
 
 static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     *ppvOut = NULL;
 
     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
     {
-        *ppvOut = This;
+        *ppvOut = &This->ITfContext_iface;
     }
     else if (IsEqualIID(iid, &IID_ITfSource))
     {
-        *ppvOut = &This->SourceVtbl;
+        *ppvOut = &This->ITfSource_iface;
     }
     else if (IsEqualIID(iid, &IID_ITfInsertAtSelection))
     {
-        *ppvOut = &This->InsertAtSelectionVtbl;
+        *ppvOut = &This->ITfInsertAtSelection_iface;
     }
     else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
     {
@@ -211,12 +164,12 @@ static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVO
     }
     else if (IsEqualIID(iid, &IID_ITfSourceSingle))
     {
-        *ppvOut = &This->SourceSingleVtbl;
+        *ppvOut = &This->ITfSourceSingle_iface;
     }
 
     if (*ppvOut)
     {
-        IUnknown_AddRef(iface);
+        ITfContext_AddRef(iface);
         return S_OK;
     }
 
@@ -226,13 +179,13 @@ static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVO
 
 static ULONG WINAPI Context_AddRef(ITfContext *iface)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     return InterlockedIncrement(&This->refCount);
 }
 
 static ULONG WINAPI Context_Release(ITfContext *iface)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     ULONG ret;
 
     ret = InterlockedDecrement(&This->refCount);
@@ -248,8 +201,8 @@ static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
         TfClientId tid, ITfEditSession *pes, DWORD dwFlags,
         HRESULT *phrSession)
 {
+    Context *This = impl_from_ITfContext(iface);
     HRESULT hr;
-    Context *This = (Context *)iface;
     DWORD  dwLockFlags = 0x0;
 
     TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession);
@@ -299,7 +252,7 @@ static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
          TfClientId tid,
          BOOL *pfWriteSession)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -308,7 +261,7 @@ static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
         TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
         TF_SELECTION *pSelection, ULONG *pcFetched)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     EditCookie *cookie;
     ULONG count, i;
     ULONG totalFetched = 0;
@@ -367,9 +320,9 @@ static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
 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;
-    Context *This = (Context *)iface;
-    INT i;
+    ULONG i;
     HRESULT hr;
 
     TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection);
@@ -405,7 +358,7 @@ static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
 static HRESULT WINAPI Context_GetStart (ITfContext *iface,
         TfEditCookie ec, ITfRange **ppStart)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     EditCookie *cookie;
     TRACE("(%p) %i %p\n",This,ec,ppStart);
 
@@ -427,7 +380,7 @@ static HRESULT WINAPI Context_GetStart (ITfContext *iface,
 static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
         TfEditCookie ec, ITfRange **ppEnd)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     EditCookie *cookie;
     LONG end;
     TRACE("(%p) %i %p\n",This,ec,ppEnd);
@@ -458,7 +411,7 @@ static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
 static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
   ITfContextView **ppView)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -466,7 +419,7 @@ static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
 static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
         IEnumTfContextViews **ppEnum)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -474,7 +427,7 @@ static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
 static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
         TF_STATUS *pdcs)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     TRACE("(%p) %p\n",This,pdcs);
 
     if (!This->connected)
@@ -499,7 +452,7 @@ static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
 static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
         REFGUID guidProp, ITfProperty **ppProp)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -507,7 +460,7 @@ static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
 static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
         REFGUID guidProp, ITfReadOnlyProperty **ppProp)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -516,7 +469,7 @@ static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
         const GUID **prgProp, ULONG cProp, const GUID **prgAppProp,
         ULONG cAppProp, ITfReadOnlyProperty **ppProperty)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -524,7 +477,7 @@ static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
 static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
         IEnumTfProperties **ppEnum)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -532,7 +485,7 @@ static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
 static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
         ITfDocumentMgr **ppDm)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     TRACE("(%p) %p\n",This,ppDm);
 
     if (!ppDm)
@@ -550,17 +503,16 @@ static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
         TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
 {
-    Context *This = (Context *)iface;
+    Context *This = impl_from_ITfContext(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
-static const ITfContextVtbl Context_ContextVtbl =
+static const ITfContextVtbl ContextVtbl =
 {
     Context_QueryInterface,
     Context_AddRef,
     Context_Release,
-
     Context_RequestEditSession,
     Context_InWriteSession,
     Context_GetSelection,
@@ -578,22 +530,22 @@ static const ITfContextVtbl Context_ContextVtbl =
     Context_CreateRangeBackup
 };
 
-static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
+static HRESULT WINAPI ContextSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
 {
-    Context *This = impl_from_ITfSourceVtbl(iface);
-    return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
+    Context *This = impl_from_ITfSource(iface);
+    return ITfContext_QueryInterface(&This->ITfContext_iface, iid, ppvOut);
 }
 
-static ULONG WINAPI Source_AddRef(ITfSource *iface)
+static ULONG WINAPI ContextSource_AddRef(ITfSource *iface)
 {
-    Context *This = impl_from_ITfSourceVtbl(iface);
-    return Context_AddRef((ITfContext *)This);
+    Context *This = impl_from_ITfSource(iface);
+    return ITfContext_AddRef(&This->ITfContext_iface);
 }
 
-static ULONG WINAPI Source_Release(ITfSource *iface)
+static ULONG WINAPI ContextSource_Release(ITfSource *iface)
 {
-    Context *This = impl_from_ITfSourceVtbl(iface);
-    return Context_Release((ITfContext *)This);
+    Context *This = impl_from_ITfSource(iface);
+    return ITfContext_Release(&This->ITfContext_iface);
 }
 
 /*****************************************************
@@ -602,64 +554,39 @@ static ULONG WINAPI Source_Release(ITfSource *iface)
 static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface,
         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
 {
-    ContextSink *es;
-    Context *This = impl_from_ITfSourceVtbl(iface);
+    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))
-    {
-        es = HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink));
-        if (!es)
-            return E_OUTOFMEMORY;
-        if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&es->interfaces.pITfTextEditSink)))
-        {
-            HeapFree(GetProcessHeap(),0,es);
-            return CONNECT_E_CANNOTCONNECT;
-        }
-        list_add_head(&This->pTextEditSink ,&es->entry);
-        *pdwCookie = generate_Cookie(COOKIE_MAGIC_CONTEXTSINK, es);
-    }
-    else
-    {
-        FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
-        return E_NOTIMPL;
-    }
+        return advise_sink(&This->pTextEditSink, &IID_ITfTextEditSink, COOKIE_MAGIC_CONTEXTSINK, punk, pdwCookie);
 
-    TRACE("cookie %x\n",*pdwCookie);
-    return S_OK;
+    FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
+    return E_NOTIMPL;
 }
 
 static HRESULT WINAPI ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
 {
-    ContextSink *sink;
-    Context *This = impl_from_ITfSourceVtbl(iface);
+    Context *This = impl_from_ITfSource(iface);
 
     TRACE("(%p) %x\n",This,pdwCookie);
 
     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
         return E_INVALIDARG;
 
-    sink = (ContextSink*)remove_Cookie(pdwCookie);
-    if (!sink)
-        return CONNECT_E_NOCONNECTION;
-
-    list_remove(&sink->entry);
-    free_sink(sink);
-
-    return S_OK;
+    return unadvise_sink(pdwCookie);
 }
 
-static const ITfSourceVtbl Context_SourceVtbl =
+static const ITfSourceVtbl ContextSourceVtbl =
 {
-    Source_QueryInterface,
-    Source_AddRef,
-    Source_Release,
-
+    ContextSource_QueryInterface,
+    ContextSource_AddRef,
+    ContextSource_Release,
     ContextSource_AdviseSink,
-    ContextSource_UnadviseSink,
+    ContextSource_UnadviseSink
 };
 
 /*****************************************************
@@ -667,27 +594,27 @@ static const ITfSourceVtbl Context_SourceVtbl =
  *****************************************************/
 static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut)
 {
-    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
-    return Context_QueryInterface((ITfContext *)This, iid, *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_ITfInsertAtSelectionVtbl(iface);
-    return Context_AddRef((ITfContext *)This);
+    Context *This = impl_from_ITfInsertAtSelection(iface);
+    return ITfContext_AddRef(&This->ITfContext_iface);
 }
 
 static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface)
 {
-    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
-    return Context_Release((ITfContext *)This);
+    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_ITfInsertAtSelectionVtbl(iface);
+    Context *This = impl_from_ITfInsertAtSelection(iface);
     EditCookie *cookie;
     LONG acpStart, acpEnd;
     TS_TEXTCHANGE change;
@@ -714,7 +641,7 @@ static HRESULT WINAPI InsertAtSelection_InsertTextAtSelection(
 
     hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change);
     if (SUCCEEDED(hr))
-        Range_Constructor((ITfContext*)This, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
+        Range_Constructor(&This->ITfContext_iface, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
 
     return hr;
 }
@@ -723,17 +650,16 @@ static HRESULT WINAPI InsertAtSelection_InsertEmbeddedAtSelection(
         ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
         IDataObject *pDataObject, ITfRange **ppRange)
 {
-    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
+    Context *This = impl_from_ITfInsertAtSelection(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
-static const ITfInsertAtSelectionVtbl Context_InsertAtSelectionVtbl =
+static const ITfInsertAtSelectionVtbl InsertAtSelectionVtbl =
 {
     InsertAtSelection_QueryInterface,
     InsertAtSelection_AddRef,
     InsertAtSelection_Release,
-
     InsertAtSelection_InsertTextAtSelection,
     InsertAtSelection_InsertEmbeddedAtSelection,
 };
@@ -743,26 +669,26 @@ static const ITfInsertAtSelectionVtbl Context_InsertAtSelectionVtbl =
  *****************************************************/
 static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
 {
-    Context *This = impl_from_ITfSourceSingleVtbl(iface);
-    return Context_QueryInterface((ITfContext *)This, iid, *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_ITfSourceSingleVtbl(iface);
-    return Context_AddRef((ITfContext *)This);
+    Context *This = impl_from_ITfSourceSingle(iface);
+    return ITfContext_AddRef(&This->ITfContext_iface);
 }
 
 static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface)
 {
-    Context *This = impl_from_ITfSourceSingleVtbl(iface);
-    return Context_Release((ITfContext *)This);
+    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_ITfSourceSingleVtbl(iface);
+    Context *This = impl_from_ITfSourceSingle(iface);
     FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
     return E_NOTIMPL;
 }
@@ -770,133 +696,40 @@ static HRESULT WINAPI SourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
 static HRESULT WINAPI SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
     TfClientId tid, REFIID riid)
 {
-    Context *This = impl_from_ITfSourceSingleVtbl(iface);
+    Context *This = impl_from_ITfSourceSingle(iface);
     FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
     return E_NOTIMPL;
 }
 
-static const ITfSourceSingleVtbl Context_SourceSingleVtbl =
+static const ITfSourceSingleVtbl ContextSourceSingleVtbl =
 {
     SourceSingle_QueryInterface,
     SourceSingle_AddRef,
     SourceSingle_Release,
-
     SourceSingle_AdviseSingleSink,
     SourceSingle_UnadviseSingleSink,
 };
 
-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->ContextVtbl= &Context_ContextVtbl;
-    This->SourceVtbl = &Context_SourceVtbl;
-    This->InsertAtSelectionVtbl = &Context_InsertAtSelectionVtbl;
-    This->SourceSingleVtbl = &Context_SourceSingleVtbl;
-    This->refCount = 1;
-    This->tidOwner = tidOwner;
-    This->connected = FALSE;
-    This->manager = mgr;
-
-    CompartmentMgr_Constructor((IUnknown*)This, &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 = (ITfContext*)This;
-    TRACE("returning %p\n", This);
-
-    return S_OK;
-}
-
-HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager)
-{
-    Context *This = (Context *)iface;
-
-    if (This->pITextStoreACP)
-    {
-        if (SUCCEEDED(TextStoreACPSink_Constructor(&This->pITextStoreACPSink, This)))
-            ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink,
-                            (IUnknown*)This->pITextStoreACPSink, TS_AS_ALL_SINKS);
-    }
-    This->connected = TRUE;
-    This->manager = manager;
-    return S_OK;
-}
-
-HRESULT Context_Uninitialize(ITfContext *iface)
-{
-    Context *This = (Context *)iface;
-
-    if (This->pITextStoreACPSink)
-    {
-        ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
-        if (ITextStoreACPSink_Release(This->pITextStoreACPSink) == 0)
-            This->pITextStoreACPSink = NULL;
-    }
-    This->connected = FALSE;
-    This->manager = NULL;
-    return S_OK;
-}
-
 /**************************************************************************
  *  ITextStoreACPSink
  **************************************************************************/
 
-static void TextStoreACPSink_Destructor(TextStoreACPSink *This)
-{
-    TRACE("destroying %p\n", This);
-    HeapFree(GetProcessHeap(),0,This);
-}
-
 static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
+
     *ppvOut = NULL;
 
     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
     {
-        *ppvOut = This;
+        *ppvOut = &This->ITextStoreACPSink_iface;
     }
+    else if (IsEqualIID(iid, &IID_ITextStoreACPServices))
+        *ppvOut = &This->ITextStoreACPServices_iface;
 
     if (*ppvOut)
     {
-        IUnknown_AddRef(iface);
+        ITextStoreACPSink_AddRef(iface);
         return S_OK;
     }
 
@@ -906,19 +739,14 @@ static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface,
 
 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
-    return InterlockedIncrement(&This->refCount);
+    Context *This = impl_from_ITextStoreACPSink(iface);
+    return ITfContext_AddRef(&This->ITfContext_iface);
 }
 
 static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
-    ULONG ret;
-
-    ret = InterlockedDecrement(&This->refCount);
-    if (ret == 0)
-        TextStoreACPSink_Destructor(This);
-    return ret;
+    Context *This = impl_from_ITextStoreACPSink(iface);
+    return ITfContext_Release(&This->ITfContext_iface);
 }
 
 /*****************************************************
@@ -928,14 +756,14 @@ static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
 static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
         DWORD dwFlags, const TS_TEXTCHANGE *pChange)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -943,7 +771,7 @@ static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *ifac
 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
     TsLayoutCode lcode, TsViewCookie vcView)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -951,27 +779,21 @@ static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
         DWORD dwFlags)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     HRESULT hr, hrSession;
 
     TRACE("(%p) %x\n",This, dwFlags);
 
-    if (!This->pContext)
-    {
-        ERR("No context?\n");
-        return E_FAIL;
-    }
-
-    if (!This->pContext->pITextStoreACP)
+    if (!This->pITextStoreACP)
     {
         FIXME("Context does not have a ITextStoreACP\n");
         return E_NOTIMPL;
     }
 
-    hr = ITextStoreACP_RequestLock(This->pContext->pITextStoreACP, TS_LF_READ, &hrSession);
+    hr = ITextStoreACP_RequestLock(This->pITextStoreACP, TS_LF_READ, &hrSession);
 
     if(SUCCEEDED(hr) && SUCCEEDED(hrSession))
-        This->pContext->documentStatus.dwDynamicFlags = dwFlags;
+        This->documentStatus.dwDynamicFlags = dwFlags;
 
     return S_OK;
 }
@@ -979,7 +801,7 @@ static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
         LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -987,7 +809,7 @@ static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
         DWORD dwLockFlags)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     HRESULT hr;
     EditCookie *cookie,*sinkcookie;
     TfEditCookie ec;
@@ -995,13 +817,7 @@ static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
 
     TRACE("(%p) %x\n",This, dwLockFlags);
 
-    if (!This->pContext)
-    {
-        ERR("OnLockGranted called without a context\n");
-        return E_FAIL;
-    }
-
-    if (!This->pContext->currentEditSession)
+    if (!This->currentEditSession)
     {
         FIXME("OnLockGranted called for something other than an EditSession\n");
         return S_OK;
@@ -1019,32 +835,31 @@ static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
     }
 
     cookie->lockType = dwLockFlags;
-    cookie->pOwningContext = This->pContext;
+    cookie->pOwningContext = This;
     ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);
 
-    hr = ITfEditSession_DoEditSession(This->pContext->currentEditSession, ec);
+    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->pContext;
+        sinkcookie->pOwningContext = This;
         sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie);
 
         /*TODO: implement ITfEditRecord */
-        LIST_FOR_EACH(cursor, &This->pContext->pTextEditSink)
+        SINK_FOR_EACH(cursor, &This->pTextEditSink, ITfTextEditSink, sink)
         {
-            ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
-            ITfTextEditSink_OnEndEdit(sink->interfaces.pITfTextEditSink,
-                                      (ITfContext*) &This->pContext, sc, NULL);
+            ITfTextEditSink_OnEndEdit(sink, (ITfContext*) &This->ITfContext_iface, sc, NULL);
         }
         sinkcookie = remove_Cookie(sc);
     }
     HeapFree(GetProcessHeap(),0,sinkcookie);
 
-    ITfEditSession_Release(This->pContext->currentEditSession);
-    This->pContext->currentEditSession = NULL;
+    ITfEditSession_Release(This->currentEditSession);
+    This->currentEditSession = NULL;
 
     /* Edit Cookie is only valid during the edit session */
     cookie = remove_Cookie(ec);
@@ -1055,24 +870,23 @@ static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
 
 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = (TextStoreACPSink *)iface;
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
-static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl =
+static const ITextStoreACPSinkVtbl TextStoreACPSinkVtbl =
 {
     TextStoreACPSink_QueryInterface,
     TextStoreACPSink_AddRef,
     TextStoreACPSink_Release,
-
     TextStoreACPSink_OnTextChange,
     TextStoreACPSink_OnSelectionChange,
     TextStoreACPSink_OnLayoutChange,
@@ -1083,20 +897,154 @@ static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl =
     TextStoreACPSink_OnEndEditTransaction
 };
 
-static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext)
+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)
 {
-    TextStoreACPSink *This;
+    Context *This = impl_from_ITextStoreACPServices(iface);
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
+    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;
 
-    This->TextStoreACPSinkVtbl= &TextStoreACPSink_TextStoreACPSinkVtbl;
+    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->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);
 
-    This->pContext = pContext;
+    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");
+    }
 
-    TRACE("returning %p\n", This);
-    *ppOut = (ITextStoreACPSink*)This;
+    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;
 }