ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / dlls / msctf / documentmgr.c
blob37d55557f55cf62b29ebc9eb37bc734e29ee015c
1 /*
2 * ITfDocumentMgr implementation
4 * Copyright 2009 Aric Stewart, CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "wine/debug.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winuser.h"
30 #include "shlwapi.h"
31 #include "winerror.h"
32 #include "objbase.h"
34 #include "msctf.h"
35 #include "msctf_internal.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
39 typedef struct tagDocumentMgr {
40 ITfDocumentMgr ITfDocumentMgr_iface;
41 ITfSource ITfSource_iface;
42 LONG refCount;
44 /* Aggregation */
45 ITfCompartmentMgr *CompartmentMgr;
47 ITfContext* initialContext;
48 ITfContext* contextStack[2]; /* limit of 2 contexts */
49 ITfThreadMgrEventSink* ThreadMgrSink;
51 struct list TransitoryExtensionSink;
52 } DocumentMgr;
54 typedef struct tagEnumTfContext {
55 IEnumTfContexts IEnumTfContexts_iface;
56 LONG refCount;
58 DWORD index;
59 DocumentMgr *docmgr;
60 } EnumTfContext;
62 static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut);
64 static inline DocumentMgr *impl_from_ITfDocumentMgr(ITfDocumentMgr *iface)
66 return CONTAINING_RECORD(iface, DocumentMgr, ITfDocumentMgr_iface);
69 static inline DocumentMgr *impl_from_ITfSource(ITfSource *iface)
71 return CONTAINING_RECORD(iface, DocumentMgr, ITfSource_iface);
74 static inline EnumTfContext *impl_from_IEnumTfContexts(IEnumTfContexts *iface)
76 return CONTAINING_RECORD(iface, EnumTfContext, IEnumTfContexts_iface);
79 static void DocumentMgr_Destructor(DocumentMgr *This)
81 ITfThreadMgr *tm = NULL;
82 TRACE("destroying %p\n", This);
84 TF_GetThreadMgr(&tm);
85 if (tm)
87 ThreadMgr_OnDocumentMgrDestruction(tm, &This->ITfDocumentMgr_iface);
88 ITfThreadMgr_Release(tm);
91 if (This->initialContext)
92 ITfContext_Release(This->initialContext);
93 if (This->contextStack[0])
94 ITfContext_Release(This->contextStack[0]);
95 if (This->contextStack[1])
96 ITfContext_Release(This->contextStack[1]);
97 free_sinks(&This->TransitoryExtensionSink);
98 CompartmentMgr_Destructor(This->CompartmentMgr);
99 HeapFree(GetProcessHeap(),0,This);
102 static HRESULT WINAPI DocumentMgr_QueryInterface(ITfDocumentMgr *iface, REFIID iid, LPVOID *ppvOut)
104 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
105 *ppvOut = NULL;
107 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfDocumentMgr))
109 *ppvOut = &This->ITfDocumentMgr_iface;
111 else if (IsEqualIID(iid, &IID_ITfSource))
113 *ppvOut = &This->ITfSource_iface;
115 else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
117 *ppvOut = This->CompartmentMgr;
120 if (*ppvOut)
122 ITfDocumentMgr_AddRef(iface);
123 return S_OK;
126 WARN("unsupported interface: %s\n", debugstr_guid(iid));
127 return E_NOINTERFACE;
130 static ULONG WINAPI DocumentMgr_AddRef(ITfDocumentMgr *iface)
132 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
133 return InterlockedIncrement(&This->refCount);
136 static ULONG WINAPI DocumentMgr_Release(ITfDocumentMgr *iface)
138 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
139 ULONG ret;
141 ret = InterlockedDecrement(&This->refCount);
142 if (ret == 0)
143 DocumentMgr_Destructor(This);
144 return ret;
147 /*****************************************************
148 * ITfDocumentMgr functions
149 *****************************************************/
150 static HRESULT WINAPI DocumentMgr_CreateContext(ITfDocumentMgr *iface,
151 TfClientId tidOwner,
152 DWORD dwFlags, IUnknown *punk, ITfContext **ppic,
153 TfEditCookie *pecTextStore)
155 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
156 TRACE("(%p) 0x%x 0x%x %p %p %p\n",This,tidOwner,dwFlags,punk,ppic,pecTextStore);
157 return Context_Constructor(tidOwner, punk, iface, ppic, pecTextStore);
160 static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic)
162 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
163 ITfContext *check;
165 TRACE("(%p) %p\n",This,pic);
167 if (This->contextStack[1]) /* FUll */
168 return TF_E_STACKFULL;
170 if (!pic || FAILED(ITfContext_QueryInterface(pic,&IID_ITfContext,(LPVOID*) &check)))
171 return E_INVALIDARG;
173 if (This->contextStack[0] == NULL)
174 ITfThreadMgrEventSink_OnInitDocumentMgr(This->ThreadMgrSink,iface);
176 This->contextStack[1] = This->contextStack[0];
177 This->contextStack[0] = check;
179 Context_Initialize(check, iface);
180 ITfThreadMgrEventSink_OnPushContext(This->ThreadMgrSink,check);
182 return S_OK;
185 static HRESULT WINAPI DocumentMgr_Pop(ITfDocumentMgr *iface, DWORD dwFlags)
187 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
188 TRACE("(%p) 0x%x\n",This,dwFlags);
190 if (dwFlags == TF_POPF_ALL)
192 int i;
194 for (i = 0; i < ARRAY_SIZE(This->contextStack); i++)
195 if (This->contextStack[i])
197 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink, This->contextStack[i]);
198 Context_Uninitialize(This->contextStack[i]);
199 ITfContext_Release(This->contextStack[i]);
200 This->contextStack[i] = NULL;
203 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface);
204 return S_OK;
207 if (dwFlags)
208 return E_INVALIDARG;
210 if (This->contextStack[1] == NULL) /* Cannot pop last context */
211 return E_FAIL;
213 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink,This->contextStack[0]);
214 Context_Uninitialize(This->contextStack[0]);
215 ITfContext_Release(This->contextStack[0]);
216 This->contextStack[0] = This->contextStack[1];
217 This->contextStack[1] = NULL;
219 if (This->contextStack[0] == NULL)
220 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface);
222 return S_OK;
225 static HRESULT WINAPI DocumentMgr_GetTop(ITfDocumentMgr *iface, ITfContext **ppic)
227 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
228 ITfContext *tgt;
230 TRACE("(%p)\n",This);
231 if (!ppic)
232 return E_INVALIDARG;
234 if (This->contextStack[0])
235 tgt = This->contextStack[0];
236 else
237 tgt = This->initialContext;
239 if (tgt)
240 ITfContext_AddRef(tgt);
242 *ppic = tgt;
244 return S_OK;
247 static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **ppic)
249 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
250 ITfContext *tgt;
252 TRACE("(%p)\n",This);
253 if (!ppic)
254 return E_INVALIDARG;
256 if (This->contextStack[1])
257 tgt = This->contextStack[1];
258 else if (This->contextStack[0])
259 tgt = This->contextStack[0];
260 else
261 tgt = This->initialContext;
263 if (tgt)
264 ITfContext_AddRef(tgt);
266 *ppic = tgt;
268 return S_OK;
271 static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum)
273 DocumentMgr *This = impl_from_ITfDocumentMgr(iface);
274 TRACE("(%p) %p\n",This,ppEnum);
275 return EnumTfContext_Constructor(This, ppEnum);
278 static const ITfDocumentMgrVtbl DocumentMgrVtbl =
280 DocumentMgr_QueryInterface,
281 DocumentMgr_AddRef,
282 DocumentMgr_Release,
283 DocumentMgr_CreateContext,
284 DocumentMgr_Push,
285 DocumentMgr_Pop,
286 DocumentMgr_GetTop,
287 DocumentMgr_GetBase,
288 DocumentMgr_EnumContexts
291 static HRESULT WINAPI DocumentMgrSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
293 DocumentMgr *This = impl_from_ITfSource(iface);
294 return ITfDocumentMgr_QueryInterface(&This->ITfDocumentMgr_iface, iid, ppvOut);
297 static ULONG WINAPI DocumentMgrSource_AddRef(ITfSource *iface)
299 DocumentMgr *This = impl_from_ITfSource(iface);
300 return ITfDocumentMgr_AddRef(&This->ITfDocumentMgr_iface);
303 static ULONG WINAPI DocumentMgrSource_Release(ITfSource *iface)
305 DocumentMgr *This = impl_from_ITfSource(iface);
306 return ITfDocumentMgr_Release(&This->ITfDocumentMgr_iface);
309 /*****************************************************
310 * ITfSource functions
311 *****************************************************/
312 static HRESULT WINAPI DocumentMgrSource_AdviseSink(ITfSource *iface,
313 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
315 DocumentMgr *This = impl_from_ITfSource(iface);
317 TRACE("(%p) %s %p %p\n", This, debugstr_guid(riid), punk, pdwCookie);
319 if (!riid || !punk || !pdwCookie)
320 return E_INVALIDARG;
322 if (IsEqualIID(riid, &IID_ITfTransitoryExtensionSink))
324 WARN("semi-stub for ITfTransitoryExtensionSink: callback won't be used.\n");
325 return advise_sink(&This->TransitoryExtensionSink, &IID_ITfTransitoryExtensionSink,
326 COOKIE_MAGIC_DMSINK, punk, pdwCookie);
329 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
330 return E_NOTIMPL;
333 static HRESULT WINAPI DocumentMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
335 DocumentMgr *This = impl_from_ITfSource(iface);
337 TRACE("(%p) %x\n",This,pdwCookie);
339 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_DMSINK)
340 return E_INVALIDARG;
342 return unadvise_sink(pdwCookie);
345 static const ITfSourceVtbl DocumentMgrSourceVtbl =
347 DocumentMgrSource_QueryInterface,
348 DocumentMgrSource_AddRef,
349 DocumentMgrSource_Release,
350 DocumentMgrSource_AdviseSink,
351 DocumentMgrSource_UnadviseSink,
354 HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumentMgr **ppOut)
356 DocumentMgr *This;
357 DWORD cookie;
359 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DocumentMgr));
360 if (This == NULL)
361 return E_OUTOFMEMORY;
363 This->ITfDocumentMgr_iface.lpVtbl = &DocumentMgrVtbl;
364 This->ITfSource_iface.lpVtbl = &DocumentMgrSourceVtbl;
365 This->refCount = 1;
366 This->ThreadMgrSink = ThreadMgrSink;
367 list_init(&This->TransitoryExtensionSink);
369 CompartmentMgr_Constructor((IUnknown*)&This->ITfDocumentMgr_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
370 Context_Constructor(processId,NULL,&This->ITfDocumentMgr_iface, &This->initialContext, &cookie);
372 *ppOut = &This->ITfDocumentMgr_iface;
373 TRACE("returning %p\n", *ppOut);
374 return S_OK;
377 /**************************************************
378 * IEnumTfContexts implementation
379 **************************************************/
380 static void EnumTfContext_Destructor(EnumTfContext *This)
382 TRACE("destroying %p\n", This);
383 HeapFree(GetProcessHeap(),0,This);
386 static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut)
388 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
389 *ppvOut = NULL;
391 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts))
393 *ppvOut = &This->IEnumTfContexts_iface;
396 if (*ppvOut)
398 IEnumTfContexts_AddRef(iface);
399 return S_OK;
402 WARN("unsupported interface: %s\n", debugstr_guid(iid));
403 return E_NOINTERFACE;
406 static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface)
408 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
409 return InterlockedIncrement(&This->refCount);
412 static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface)
414 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
415 ULONG ret;
417 ret = InterlockedDecrement(&This->refCount);
418 if (ret == 0)
419 EnumTfContext_Destructor(This);
420 return ret;
423 static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface,
424 ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched)
426 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
427 ULONG fetched = 0;
429 TRACE("(%p)\n",This);
431 if (rgContext == NULL) return E_POINTER;
433 while (fetched < ulCount)
435 if (This->index > 1)
436 break;
438 if (!This->docmgr->contextStack[This->index])
439 break;
441 *rgContext = This->docmgr->contextStack[This->index];
442 ITfContext_AddRef(*rgContext);
444 ++This->index;
445 ++fetched;
446 ++rgContext;
449 if (pcFetched) *pcFetched = fetched;
450 return fetched == ulCount ? S_OK : S_FALSE;
453 static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt)
455 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
456 TRACE("(%p)\n",This);
457 This->index += celt;
458 return S_OK;
461 static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface)
463 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
464 TRACE("(%p)\n",This);
465 This->index = 0;
466 return S_OK;
469 static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface,
470 IEnumTfContexts **ppenum)
472 EnumTfContext *This = impl_from_IEnumTfContexts(iface);
473 HRESULT res;
475 TRACE("(%p)\n",This);
477 if (ppenum == NULL) return E_POINTER;
479 res = EnumTfContext_Constructor(This->docmgr, ppenum);
480 if (SUCCEEDED(res))
482 EnumTfContext *new_This = impl_from_IEnumTfContexts(*ppenum);
483 new_This->index = This->index;
485 return res;
488 static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={
489 EnumTfContext_QueryInterface,
490 EnumTfContext_AddRef,
491 EnumTfContext_Release,
493 EnumTfContext_Clone,
494 EnumTfContext_Next,
495 EnumTfContext_Reset,
496 EnumTfContext_Skip
499 static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut)
501 EnumTfContext *This;
503 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext));
504 if (This == NULL)
505 return E_OUTOFMEMORY;
507 This->IEnumTfContexts_iface.lpVtbl = &IEnumTfContexts_Vtbl;
508 This->refCount = 1;
509 This->docmgr = mgr;
511 *ppOut = &This->IEnumTfContexts_iface;
512 TRACE("returning %p\n", *ppOut);
513 return S_OK;