qcap/tests: Add media tests for the SmartTee filter.
[wine/multimedia.git] / dlls / msctf / compartmentmgr.c
blob81826796d073aad09854e461e30a3287d677e601
1 /*
2 * ITfCompartmentMgr 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 "config.h"
23 #include <stdarg.h>
25 #define COBJMACROS
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "shlwapi.h"
33 #include "winerror.h"
34 #include "objbase.h"
35 #include "oleauto.h"
36 #include "olectl.h"
38 #include "wine/unicode.h"
39 #include "wine/list.h"
41 #include "msctf.h"
42 #include "msctf_internal.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
46 typedef struct tagCompartmentValue {
47 struct list entry;
48 GUID guid;
49 TfClientId owner;
50 ITfCompartment *compartment;
51 } CompartmentValue;
53 typedef struct tagCompartmentMgr {
54 ITfCompartmentMgr ITfCompartmentMgr_iface;
55 LONG refCount;
57 IUnknown *pUnkOuter;
59 struct list values;
60 } CompartmentMgr;
62 typedef struct tagCompartmentEnumGuid {
63 IEnumGUID IEnumGUID_iface;
64 LONG refCount;
66 struct list *values;
67 struct list *cursor;
68 } CompartmentEnumGuid;
71 typedef struct tagCompartmentSink {
72 struct list entry;
73 union {
74 IUnknown *pIUnknown;
75 ITfCompartmentEventSink *pITfCompartmentEventSink;
76 } interfaces;
77 } CompartmentSink;
79 typedef struct tagCompartment {
80 ITfCompartment ITfCompartment_iface;
81 ITfSource ITfSource_iface;
82 LONG refCount;
84 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
85 VARIANT variant;
86 CompartmentValue *valueData;
87 struct list CompartmentEventSink;
88 } Compartment;
90 static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut);
91 static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut);
93 static inline CompartmentMgr *impl_from_ITfCompartmentMgr(ITfCompartmentMgr *iface)
95 return CONTAINING_RECORD(iface, CompartmentMgr, ITfCompartmentMgr_iface);
98 static inline Compartment *impl_from_ITfCompartment(ITfCompartment *iface)
100 return CONTAINING_RECORD(iface, Compartment, ITfCompartment_iface);
103 static inline Compartment *impl_from_ITfSource(ITfSource *iface)
105 return CONTAINING_RECORD(iface, Compartment, ITfSource_iface);
108 static inline CompartmentEnumGuid *impl_from_IEnumGUID(IEnumGUID *iface)
110 return CONTAINING_RECORD(iface, CompartmentEnumGuid, IEnumGUID_iface);
113 HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface)
115 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
116 struct list *cursor, *cursor2;
118 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values)
120 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
121 list_remove(cursor);
122 ITfCompartment_Release(value->compartment);
123 HeapFree(GetProcessHeap(),0,value);
126 HeapFree(GetProcessHeap(),0,This);
127 return S_OK;
130 /*****************************************************
131 * ITfCompartmentMgr functions
132 *****************************************************/
133 static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut)
135 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
136 if (This->pUnkOuter)
137 return IUnknown_QueryInterface(This->pUnkOuter, iid, ppvOut);
138 else
140 *ppvOut = NULL;
142 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr))
144 *ppvOut = &This->ITfCompartmentMgr_iface;
147 if (*ppvOut)
149 ITfCompartmentMgr_AddRef(iface);
150 return S_OK;
153 WARN("unsupported interface: %s\n", debugstr_guid(iid));
154 return E_NOINTERFACE;
158 static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface)
160 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
161 if (This->pUnkOuter)
162 return IUnknown_AddRef(This->pUnkOuter);
163 else
164 return InterlockedIncrement(&This->refCount);
167 static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface)
169 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
170 if (This->pUnkOuter)
171 return IUnknown_Release(This->pUnkOuter);
172 else
174 ULONG ret;
176 ret = InterlockedDecrement(&This->refCount);
177 if (ret == 0)
178 CompartmentMgr_Destructor(iface);
179 return ret;
183 static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface,
184 REFGUID rguid, ITfCompartment **ppcomp)
186 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
187 CompartmentValue* value;
188 struct list *cursor;
189 HRESULT hr;
191 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),ppcomp);
193 LIST_FOR_EACH(cursor, &This->values)
195 value = LIST_ENTRY(cursor,CompartmentValue,entry);
196 if (IsEqualGUID(rguid,&value->guid))
198 ITfCompartment_AddRef(value->compartment);
199 *ppcomp = value->compartment;
200 return S_OK;
204 value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue));
205 value->guid = *rguid;
206 value->owner = 0;
207 hr = Compartment_Constructor(value,&value->compartment);
208 if (SUCCEEDED(hr))
210 list_add_head(&This->values,&value->entry);
211 ITfCompartment_AddRef(value->compartment);
212 *ppcomp = value->compartment;
214 else
216 HeapFree(GetProcessHeap(),0,value);
217 *ppcomp = NULL;
219 return hr;
222 static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface,
223 TfClientId tid, REFGUID rguid)
225 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
226 struct list *cursor;
228 TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid));
230 LIST_FOR_EACH(cursor, &This->values)
232 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
233 if (IsEqualGUID(rguid,&value->guid))
235 if (value->owner && tid != value->owner)
236 return E_UNEXPECTED;
237 list_remove(cursor);
238 ITfCompartment_Release(value->compartment);
239 HeapFree(GetProcessHeap(),0,value);
240 return S_OK;
244 return CONNECT_E_NOCONNECTION;
247 static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface,
248 IEnumGUID **ppEnum)
250 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
252 TRACE("(%p) %p\n",This,ppEnum);
253 if (!ppEnum)
254 return E_INVALIDARG;
255 return CompartmentEnumGuid_Constructor(&This->values, ppEnum);
258 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl =
260 CompartmentMgr_QueryInterface,
261 CompartmentMgr_AddRef,
262 CompartmentMgr_Release,
263 CompartmentMgr_GetCompartment,
264 CompartmentMgr_ClearCompartment,
265 CompartmentMgr_EnumCompartments
268 HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut)
270 CompartmentMgr *This;
272 if (!ppOut)
273 return E_POINTER;
275 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
276 return CLASS_E_NOAGGREGATION;
278 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr));
279 if (This == NULL)
280 return E_OUTOFMEMORY;
282 This->ITfCompartmentMgr_iface.lpVtbl = &CompartmentMgrVtbl;
283 This->pUnkOuter = pUnkOuter;
284 list_init(&This->values);
286 if (pUnkOuter)
288 *ppOut = (IUnknown*)&This->ITfCompartmentMgr_iface;
289 TRACE("returning %p\n", *ppOut);
290 return S_OK;
292 else
294 HRESULT hr;
295 hr = ITfCompartmentMgr_QueryInterface(&This->ITfCompartmentMgr_iface, riid, (void**)ppOut);
296 if (FAILED(hr))
297 HeapFree(GetProcessHeap(),0,This);
298 return hr;
302 /**************************************************
303 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
304 **************************************************/
305 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This)
307 TRACE("destroying %p\n", This);
308 HeapFree(GetProcessHeap(),0,This);
311 static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
313 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
314 *ppvOut = NULL;
316 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
318 *ppvOut = &This->IEnumGUID_iface;
321 if (*ppvOut)
323 IEnumGUID_AddRef(iface);
324 return S_OK;
327 WARN("unsupported interface: %s\n", debugstr_guid(iid));
328 return E_NOINTERFACE;
331 static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface)
333 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
334 return InterlockedIncrement(&This->refCount);
337 static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface)
339 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
340 ULONG ret;
342 ret = InterlockedDecrement(&This->refCount);
343 if (ret == 0)
344 CompartmentEnumGuid_Destructor(This);
345 return ret;
348 /*****************************************************
349 * IEnumGuid functions
350 *****************************************************/
351 static HRESULT WINAPI CompartmentEnumGuid_Next(IEnumGUID *iface,
352 ULONG celt, GUID *rgelt, ULONG *pceltFetched)
354 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
355 ULONG fetched = 0;
357 TRACE("(%p)\n",This);
359 if (rgelt == NULL) return E_POINTER;
361 while (fetched < celt && This->cursor)
363 CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry);
364 if (!value)
365 break;
367 This->cursor = list_next(This->values,This->cursor);
368 *rgelt = value->guid;
370 ++fetched;
371 ++rgelt;
374 if (pceltFetched) *pceltFetched = fetched;
375 return fetched == celt ? S_OK : S_FALSE;
378 static HRESULT WINAPI CompartmentEnumGuid_Skip(IEnumGUID *iface, ULONG celt)
380 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
381 TRACE("(%p)\n",This);
383 This->cursor = list_next(This->values,This->cursor);
384 return S_OK;
387 static HRESULT WINAPI CompartmentEnumGuid_Reset(IEnumGUID *iface)
389 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
390 TRACE("(%p)\n",This);
391 This->cursor = list_head(This->values);
392 return S_OK;
395 static HRESULT WINAPI CompartmentEnumGuid_Clone(IEnumGUID *iface,
396 IEnumGUID **ppenum)
398 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
399 HRESULT res;
401 TRACE("(%p)\n",This);
403 if (ppenum == NULL) return E_POINTER;
405 res = CompartmentEnumGuid_Constructor(This->values, ppenum);
406 if (SUCCEEDED(res))
408 CompartmentEnumGuid *new_This = impl_from_IEnumGUID(*ppenum);
409 new_This->cursor = This->cursor;
411 return res;
414 static const IEnumGUIDVtbl EnumGUIDVtbl =
416 CompartmentEnumGuid_QueryInterface,
417 CompartmentEnumGuid_AddRef,
418 CompartmentEnumGuid_Release,
419 CompartmentEnumGuid_Next,
420 CompartmentEnumGuid_Skip,
421 CompartmentEnumGuid_Reset,
422 CompartmentEnumGuid_Clone
425 static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut)
427 CompartmentEnumGuid *This;
429 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid));
430 if (This == NULL)
431 return E_OUTOFMEMORY;
433 This->IEnumGUID_iface.lpVtbl= &EnumGUIDVtbl;
434 This->refCount = 1;
436 This->values = values;
437 This->cursor = list_head(values);
439 *ppOut = &This->IEnumGUID_iface;
440 TRACE("returning %p\n", *ppOut);
441 return S_OK;
444 /**************************************************
445 * ITfCompartment
446 **************************************************/
447 static void free_sink(CompartmentSink *sink)
449 IUnknown_Release(sink->interfaces.pIUnknown);
450 HeapFree(GetProcessHeap(),0,sink);
453 static void Compartment_Destructor(Compartment *This)
455 struct list *cursor, *cursor2;
456 TRACE("destroying %p\n", This);
457 VariantClear(&This->variant);
458 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CompartmentEventSink)
460 CompartmentSink* sink = LIST_ENTRY(cursor,CompartmentSink,entry);
461 list_remove(cursor);
462 free_sink(sink);
464 HeapFree(GetProcessHeap(),0,This);
467 static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut)
469 Compartment *This = impl_from_ITfCompartment(iface);
471 *ppvOut = NULL;
473 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment))
475 *ppvOut = &This->ITfCompartment_iface;
477 else if (IsEqualIID(iid, &IID_ITfSource))
479 *ppvOut = &This->ITfSource_iface;
482 if (*ppvOut)
484 ITfCompartment_AddRef(iface);
485 return S_OK;
488 WARN("unsupported interface: %s\n", debugstr_guid(iid));
489 return E_NOINTERFACE;
492 static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface)
494 Compartment *This = impl_from_ITfCompartment(iface);
495 return InterlockedIncrement(&This->refCount);
498 static ULONG WINAPI Compartment_Release(ITfCompartment *iface)
500 Compartment *This = impl_from_ITfCompartment(iface);
501 ULONG ret;
503 ret = InterlockedDecrement(&This->refCount);
504 if (ret == 0)
505 Compartment_Destructor(This);
506 return ret;
509 static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface,
510 TfClientId tid, const VARIANT *pvarValue)
512 Compartment *This = impl_from_ITfCompartment(iface);
513 struct list *cursor;
515 TRACE("(%p) %i %p\n",This,tid,pvarValue);
517 if (!pvarValue)
518 return E_INVALIDARG;
520 if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 ||
521 V_VT(pvarValue) == VT_UNKNOWN))
522 return E_INVALIDARG;
524 if (!This->valueData->owner)
525 This->valueData->owner = tid;
527 VariantClear(&This->variant);
529 /* Shallow copy of value and type */
530 This->variant = *pvarValue;
532 if (V_VT(pvarValue) == VT_BSTR)
533 V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue),
534 SysStringByteLen(V_BSTR(pvarValue)));
535 else if (V_VT(pvarValue) == VT_UNKNOWN)
536 IUnknown_AddRef(V_UNKNOWN(&This->variant));
538 LIST_FOR_EACH(cursor, &This->CompartmentEventSink)
540 CompartmentSink* sink = LIST_ENTRY(cursor,CompartmentSink,entry);
541 ITfCompartmentEventSink_OnChange(sink->interfaces.pITfCompartmentEventSink,&This->valueData->guid);
544 return S_OK;
547 static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface,
548 VARIANT *pvarValue)
550 Compartment *This = impl_from_ITfCompartment(iface);
551 TRACE("(%p) %p\n",This, pvarValue);
553 if (!pvarValue)
554 return E_INVALIDARG;
556 VariantInit(pvarValue);
557 if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE;
558 return VariantCopy(pvarValue,&This->variant);
561 static const ITfCompartmentVtbl CompartmentVtbl =
563 Compartment_QueryInterface,
564 Compartment_AddRef,
565 Compartment_Release,
566 Compartment_SetValue,
567 Compartment_GetValue
570 /*****************************************************
571 * ITfSource functions
572 *****************************************************/
574 static HRESULT WINAPI CompartmentSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
576 Compartment *This = impl_from_ITfSource(iface);
577 return ITfCompartment_QueryInterface(&This->ITfCompartment_iface, iid, ppvOut);
580 static ULONG WINAPI CompartmentSource_AddRef(ITfSource *iface)
582 Compartment *This = impl_from_ITfSource(iface);
583 return ITfCompartment_AddRef(&This->ITfCompartment_iface);
586 static ULONG WINAPI CompartmentSource_Release(ITfSource *iface)
588 Compartment *This = impl_from_ITfSource(iface);
589 return ITfCompartment_Release(&This->ITfCompartment_iface);
592 static HRESULT WINAPI CompartmentSource_AdviseSink(ITfSource *iface,
593 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
595 Compartment *This = impl_from_ITfSource(iface);
596 CompartmentSink *cs;
598 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
600 if (!riid || !punk || !pdwCookie)
601 return E_INVALIDARG;
603 if (IsEqualIID(riid, &IID_ITfCompartmentEventSink))
605 cs = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink));
606 if (!cs)
607 return E_OUTOFMEMORY;
608 if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&cs->interfaces.pITfCompartmentEventSink)))
610 HeapFree(GetProcessHeap(),0,cs);
611 return CONNECT_E_CANNOTCONNECT;
613 list_add_head(&This->CompartmentEventSink,&cs->entry);
614 *pdwCookie = generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK , cs);
616 else
618 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
619 return E_NOTIMPL;
622 TRACE("cookie %x\n",*pdwCookie);
624 return S_OK;
627 static HRESULT WINAPI CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
629 Compartment *This = impl_from_ITfSource(iface);
630 CompartmentSink *sink;
632 TRACE("(%p) %x\n",This,pdwCookie);
634 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK)
635 return E_INVALIDARG;
637 sink = remove_Cookie(pdwCookie);
638 if (!sink)
639 return CONNECT_E_NOCONNECTION;
641 list_remove(&sink->entry);
642 free_sink(sink);
644 return S_OK;
647 static const ITfSourceVtbl CompartmentSourceVtbl =
649 CompartmentSource_QueryInterface,
650 CompartmentSource_AddRef,
651 CompartmentSource_Release,
652 CompartmentSource_AdviseSink,
653 CompartmentSource_UnadviseSink,
656 static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut)
658 Compartment *This;
660 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment));
661 if (This == NULL)
662 return E_OUTOFMEMORY;
664 This->ITfCompartment_iface.lpVtbl= &CompartmentVtbl;
665 This->ITfSource_iface.lpVtbl = &CompartmentSourceVtbl;
666 This->refCount = 1;
668 This->valueData = valueData;
669 VariantInit(&This->variant);
671 list_init(&This->CompartmentEventSink);
673 *ppOut = &This->ITfCompartment_iface;
674 TRACE("returning %p\n", *ppOut);
675 return S_OK;