diff --git a/dlls/msctf/documentmgr.c b/dlls/msctf/documentmgr.c index f5ea71fb130..66f0f508b51 100644 --- a/dlls/msctf/documentmgr.c +++ b/dlls/msctf/documentmgr.c @@ -52,6 +52,16 @@ typedef struct tagDocumentMgr { 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_GetBase(ITfDocumentMgr *iface, ITfContext **pp 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 @@ HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumen *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; +} diff --git a/dlls/msctf/tests/inputprocessor.c b/dlls/msctf/tests/inputprocessor.c index ba4357066c8..9b266ba6bc4 100644 --- a/dlls/msctf/tests/inputprocessor.c +++ b/dlls/msctf/tests/inputprocessor.c @@ -1113,6 +1113,35 @@ static void test_Activate(void) ok(SUCCEEDED(hr),"Failed to Activate text service\n"); } + +static void test_EnumContexts(ITfDocumentMgr *dm, ITfContext *search) +{ + HRESULT hr; + IEnumTfContexts* pEnum; + BOOL found = FALSE; + + hr = ITfDocumentMgr_EnumContexts(dm,&pEnum); + ok(SUCCEEDED(hr),"EnumContexts failed\n"); + if (SUCCEEDED(hr)) + { + ULONG fetched; + ITfContext *cxt; + while (IEnumTfContexts_Next(pEnum, 1, &cxt, &fetched) == S_OK) + { + if (!search) + found = TRUE; + else if (search == cxt) + found = TRUE; + ITfContext_Release(cxt); + } + IEnumTfContexts_Release(pEnum); + } + if (search) + ok(found,"Did not find proper ITfContext\n"); + else + ok(!found,"Found an ITfContext we should should not have\n"); +} + static inline int check_context_refcount(ITfContext *iface) { IUnknown_AddRef(iface); @@ -1183,6 +1212,8 @@ static void test_startSession(void) hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt3, &editCookie); ok(SUCCEEDED(hr),"CreateContext Failed\n"); + test_EnumContexts(g_dm, NULL); + hr = ITfContext_GetDocumentMgr(cxt,&dmtest); ok(hr == S_OK, "ITfContext_GetDocumentMgr failed with %x\n",hr); ok(dmtest == g_dm, "Wrong documentmgr\n"); @@ -1199,6 +1230,8 @@ static void test_startSession(void) ok(test_OnInitDocumentMgr == SINK_FIRED, "OnInitDocumentMgr sink not fired\n"); ok(test_ACP_AdviseSink == SINK_FIRED,"TextStoreACP_AdviseSink not fired\n"); + test_EnumContexts(g_dm, cxt); + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); ok(SUCCEEDED(hr),"GetTop Failed\n"); ok(cxtTest == cxt, "Wrong context on top\n"); diff --git a/include/msctf.idl b/include/msctf.idl index ef362e0f9e5..6b341d26c9c 100644 --- a/include/msctf.idl +++ b/include/msctf.idl @@ -953,3 +953,24 @@ interface ITfCompartmentEventSink : IUnknown HRESULT OnChange( [in] REFGUID rguid); } + +[ + object, + uuid(8f1a7ea6-1654-4502-a86e-b2902344d507), + pointer_default(unique) +] +interface IEnumTfContexts : IUnknown +{ + HRESULT Clone( + [out] IEnumTfContexts **ppEnum); + + HRESULT Next( + [in] ULONG ulCount, + [out, size_is(ulCount), length_is(*pcFetched)] ITfContext **rgContext, + [out] ULONG *pcFetched); + + HRESULT Reset(); + + HRESULT Skip( + [in] ULONG ulCount); +};