msctf: Implement ITfDocumentMgr::EnumContexts.
diff --git a/dlls/msctf/documentmgr.c b/dlls/msctf/documentmgr.c
index f5ea71f..66f0f50 100644
--- a/dlls/msctf/documentmgr.c
+++ b/dlls/msctf/documentmgr.c
@@ -52,6 +52,16 @@
     ITfThreadMgrEventSink* ThreadMgrSink;
 } DocumentMgr;
 
+typedef struct tagEnumTfContext {
+    const IEnumTfContextsVtbl *Vtbl;
+    LONG refCount;
+
+    DWORD   index;
+    DocumentMgr *docmgr;
+} EnumTfContext;
+
+static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut);
+
 static inline DocumentMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
 {
     return (DocumentMgr *)((char *)iface - FIELD_OFFSET(DocumentMgr,SourceVtbl));
@@ -233,8 +243,8 @@
 static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum)
 {
     DocumentMgr *This = (DocumentMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %p\n",This,ppEnum);
+    return EnumTfContext_Constructor(This, ppEnum);
 }
 
 static const ITfDocumentMgrVtbl DocumentMgr_DocumentMgrVtbl =
@@ -317,3 +327,142 @@
     *ppOut = (ITfDocumentMgr*)This;
     return S_OK;
 }
+
+/**************************************************
+ * IEnumTfContexts implementaion
+ **************************************************/
+static void EnumTfContext_Destructor(EnumTfContext *This)
+{
+    TRACE("destroying %p\n", This);
+    HeapFree(GetProcessHeap(),0,This);
+}
+
+static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts))
+    {
+        *ppvOut = This;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("unsupported interface: %s\n", debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface)
+{
+    EnumTfContext *This = (EnumTfContext*)iface;
+    return InterlockedIncrement(&This->refCount);
+}
+
+static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        EnumTfContext_Destructor(This);
+    return ret;
+}
+
+static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface,
+    ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    ULONG fetched = 0;
+
+    TRACE("(%p)\n",This);
+
+    if (rgContext == NULL) return E_POINTER;
+
+    while (fetched < ulCount)
+    {
+        if (This->index > 1)
+            break;
+
+        if (!This->docmgr->contextStack[This->index])
+            break;
+
+        *rgContext = This->docmgr->contextStack[This->index];
+        ITfContext_AddRef(*rgContext);
+
+        ++This->index;
+        ++fetched;
+        ++rgContext;
+    }
+
+    if (pcFetched) *pcFetched = fetched;
+    return fetched == ulCount ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    TRACE("(%p)\n",This);
+    This->index += celt;
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    TRACE("(%p)\n",This);
+    This->index = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface,
+    IEnumTfContexts **ppenum)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    HRESULT res;
+
+    TRACE("(%p)\n",This);
+
+    if (ppenum == NULL) return E_POINTER;
+
+    res = EnumTfContext_Constructor(This->docmgr, ppenum);
+    if (SUCCEEDED(res))
+    {
+        EnumTfContext *new_This = (EnumTfContext *)*ppenum;
+        new_This->index = This->index;
+    }
+    return res;
+}
+
+static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={
+    EnumTfContext_QueryInterface,
+    EnumTfContext_AddRef,
+    EnumTfContext_Release,
+
+    EnumTfContext_Clone,
+    EnumTfContext_Next,
+    EnumTfContext_Reset,
+    EnumTfContext_Skip
+};
+
+static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut)
+{
+    EnumTfContext *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->Vtbl= &IEnumTfContexts_Vtbl;
+    This->refCount = 1;
+    This->docmgr = mgr;
+
+    TRACE("returning %p\n", This);
+    *ppOut = (IEnumTfContexts*)This;
+    return S_OK;
+}