[MSCTF] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / msctf / context.c
index 8d03749..54052f6 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+
+#include <stdarg.h>
+
+#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 "wine/unicode.h"
+
+#include "msctf.h"
 #include "msctf_internal.h"
 
-typedef struct tagContextSink {
-    struct list         entry;
-    union {
-        /* Context Sinks */
-        IUnknown            *pIUnknown;
-        /* ITfContextKeyEventSink  *pITfContextKeyEventSink; */
-        /* ITfEditTransactionSink  *pITfEditTransactionSink; */
-        /* ITfStatusSink           *pITfStatusSink; */
-        ITfTextEditSink     *pITfTextEditSink;
-        /* ITfTextLayoutSink       *pITfTextLayoutSink; */
-    } interfaces;
-} ContextSink;
+WINE_DEFAULT_DEBUG_CHANNEL(msctf);
 
 typedef struct tagContext {
     ITfContext ITfContext_iface;
@@ -43,6 +51,8 @@ typedef struct tagContext {
     /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
     /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
     ITfSourceSingle ITfSourceSingle_iface;
+    ITextStoreACPSink ITextStoreACPSink_iface;
+    ITextStoreACPServices ITextStoreACPServices_iface;
     LONG refCount;
     BOOL connected;
 
@@ -57,7 +67,6 @@ typedef struct tagContext {
     ITextStoreACP   *pITextStoreACP;
     ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
 
-    ITextStoreACPSink *pITextStoreACPSink;
     ITfEditSession* currentEditSession;
 
     /* kept as separate lists to reduce unnecessary iterations */
@@ -74,17 +83,6 @@ typedef struct tagEditCookie {
     Context *pOwningContext;
 } EditCookie;
 
-typedef struct tagTextStoreACPSink {
-    ITextStoreACPSink ITextStoreACPSink_iface;
-    /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
-    LONG refCount;
-
-    Context *pContext;
-} TextStoreACPSink;
-
-
-static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);
-
 static inline Context *impl_from_ITfContext(ITfContext *iface)
 {
     return CONTAINING_RECORD(iface, Context, ITfContext_iface);
@@ -105,29 +103,21 @@ static inline Context *impl_from_ITfSourceSingle(ITfSourceSingle* iface)
     return CONTAINING_RECORD(iface, Context, ITfSourceSingle_iface);
 }
 
-static inline TextStoreACPSink *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface)
+static inline Context *impl_from_ITextStoreACPSink(ITextStoreACPSink *iface)
 {
-    return CONTAINING_RECORD(iface, TextStoreACPSink, ITextStoreACPSink_iface);
+    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)
         ITextStoreACP_Release(This->pITextStoreACP);
 
@@ -141,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);
@@ -590,53 +555,29 @@ static HRESULT WINAPI ContextSource_AdviseSink(ITfSource *iface,
         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
 {
     Context *This = impl_from_ITfSource(iface);
-    ContextSink *es;
+
     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)
 {
     Context *This = impl_from_ITfSource(iface);
-    ContextSink *sink;
 
     TRACE("(%p) %x\n",This,pdwCookie);
 
     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
         return E_INVALIDARG;
 
-    sink = 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 ContextSourceVtbl =
@@ -769,114 +710,22 @@ static const ITfSourceSingleVtbl ContextSourceSingleVtbl =
     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->ITfContext_iface.lpVtbl= &ContextVtbl;
-    This->ITfSource_iface.lpVtbl = &ContextSourceVtbl;
-    This->ITfInsertAtSelection_iface.lpVtbl = &InsertAtSelectionVtbl;
-    This->ITfSourceSingle_iface.lpVtbl = &ContextSourceSingleVtbl;
-    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)
-    {
-        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 = impl_from_ITfContext(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 = impl_from_ITextStoreACPSink(iface);
+    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)
     {
@@ -890,19 +739,14 @@ static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface,
 
 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(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 = impl_from_ITextStoreACPSink(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);
 }
 
 /*****************************************************
@@ -912,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 = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -927,7 +771,7 @@ static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *ifac
 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
     TsLayoutCode lcode, TsViewCookie vcView)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -935,27 +779,21 @@ static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
         DWORD dwFlags)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(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;
 }
@@ -963,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 = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -971,7 +809,7 @@ static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
         DWORD dwLockFlags)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     HRESULT hr;
     EditCookie *cookie,*sinkcookie;
     TfEditCookie ec;
@@ -979,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;
@@ -1003,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);
@@ -1039,14 +870,14 @@ static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
 
 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
 {
-    TextStoreACPSink *This = impl_from_ITextStoreACPSink(iface);
+    Context *This = impl_from_ITextStoreACPSink(iface);
     FIXME("STUB:(%p)\n",This);
     return E_NOTIMPL;
 }
@@ -1066,20 +897,154 @@ static const ITextStoreACPSinkVtbl 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)
+{
+    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)
 {
-    TextStoreACPSink *This;
+    Context *This;
+    EditCookie *cookie;
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
     if (This == NULL)
         return E_OUTOFMEMORY;
 
-    This->ITextStoreACPSink_iface.lpVtbl= &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);
+
+    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;
 
-    This->pContext = pContext;
+    list_init(&This->pContextKeyEventSink);
+    list_init(&This->pEditTransactionSink);
+    list_init(&This->pStatusSink);
+    list_init(&This->pTextEditSink);
+    list_init(&This->pTextLayoutSink);
 
-    *ppOut = &This->ITextStoreACPSink_iface;
+    *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;
 }