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 "msctf_internal.h"
25 typedef struct tagCompartmentValue
{
29 ITfCompartment
*compartment
;
32 typedef struct tagCompartmentMgr
{
33 ITfCompartmentMgr ITfCompartmentMgr_iface
;
41 typedef struct tagCompartmentEnumGuid
{
42 IEnumGUID IEnumGUID_iface
;
47 } CompartmentEnumGuid
;
50 typedef struct tagCompartmentSink
{
54 ITfCompartmentEventSink
*pITfCompartmentEventSink
;
58 typedef struct tagCompartment
{
59 ITfCompartment ITfCompartment_iface
;
60 ITfSource ITfSource_iface
;
63 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
65 CompartmentValue
*valueData
;
66 struct list CompartmentEventSink
;
69 static HRESULT
CompartmentEnumGuid_Constructor(struct list
* values
, IEnumGUID
**ppOut
);
70 static HRESULT
Compartment_Constructor(CompartmentValue
*value
, ITfCompartment
**ppOut
);
72 static inline CompartmentMgr
*impl_from_ITfCompartmentMgr(ITfCompartmentMgr
*iface
)
74 return CONTAINING_RECORD(iface
, CompartmentMgr
, ITfCompartmentMgr_iface
);
77 static inline Compartment
*impl_from_ITfCompartment(ITfCompartment
*iface
)
79 return CONTAINING_RECORD(iface
, Compartment
, ITfCompartment_iface
);
82 static inline Compartment
*impl_from_ITfSource(ITfSource
*iface
)
84 return CONTAINING_RECORD(iface
, Compartment
, ITfSource_iface
);
87 static inline CompartmentEnumGuid
*impl_from_IEnumGUID(IEnumGUID
*iface
)
89 return CONTAINING_RECORD(iface
, CompartmentEnumGuid
, IEnumGUID_iface
);
92 HRESULT
CompartmentMgr_Destructor(ITfCompartmentMgr
*iface
)
94 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
95 struct list
*cursor
, *cursor2
;
97 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->values
)
99 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
101 ITfCompartment_Release(value
->compartment
);
102 HeapFree(GetProcessHeap(),0,value
);
105 HeapFree(GetProcessHeap(),0,This
);
109 /*****************************************************
110 * ITfCompartmentMgr functions
111 *****************************************************/
112 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
114 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
116 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, ppvOut
);
121 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
123 *ppvOut
= &This
->ITfCompartmentMgr_iface
;
128 ITfCompartmentMgr_AddRef(iface
);
132 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
133 return E_NOINTERFACE
;
137 static ULONG WINAPI
CompartmentMgr_AddRef(ITfCompartmentMgr
*iface
)
139 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
141 return IUnknown_AddRef(This
->pUnkOuter
);
143 return InterlockedIncrement(&This
->refCount
);
146 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
148 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
150 return IUnknown_Release(This
->pUnkOuter
);
155 ret
= InterlockedDecrement(&This
->refCount
);
157 CompartmentMgr_Destructor(iface
);
162 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
163 REFGUID rguid
, ITfCompartment
**ppcomp
)
165 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
166 CompartmentValue
* value
;
170 TRACE("(%p) %s %p\n",This
,debugstr_guid(rguid
),ppcomp
);
172 LIST_FOR_EACH(cursor
, &This
->values
)
174 value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
175 if (IsEqualGUID(rguid
,&value
->guid
))
177 ITfCompartment_AddRef(value
->compartment
);
178 *ppcomp
= value
->compartment
;
183 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
184 value
->guid
= *rguid
;
186 hr
= Compartment_Constructor(value
,&value
->compartment
);
189 list_add_head(&This
->values
,&value
->entry
);
190 ITfCompartment_AddRef(value
->compartment
);
191 *ppcomp
= value
->compartment
;
195 HeapFree(GetProcessHeap(),0,value
);
201 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
202 TfClientId tid
, REFGUID rguid
)
204 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
207 TRACE("(%p) %i %s\n",This
,tid
,debugstr_guid(rguid
));
209 LIST_FOR_EACH(cursor
, &This
->values
)
211 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
212 if (IsEqualGUID(rguid
,&value
->guid
))
214 if (value
->owner
&& tid
!= value
->owner
)
217 ITfCompartment_Release(value
->compartment
);
218 HeapFree(GetProcessHeap(),0,value
);
223 return CONNECT_E_NOCONNECTION
;
226 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
229 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
231 TRACE("(%p) %p\n",This
,ppEnum
);
234 return CompartmentEnumGuid_Constructor(&This
->values
, ppEnum
);
237 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl
=
239 CompartmentMgr_QueryInterface
,
240 CompartmentMgr_AddRef
,
241 CompartmentMgr_Release
,
242 CompartmentMgr_GetCompartment
,
243 CompartmentMgr_ClearCompartment
,
244 CompartmentMgr_EnumCompartments
247 HRESULT
CompartmentMgr_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, IUnknown
**ppOut
)
249 CompartmentMgr
*This
;
254 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
255 return CLASS_E_NOAGGREGATION
;
257 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
259 return E_OUTOFMEMORY
;
261 This
->ITfCompartmentMgr_iface
.lpVtbl
= &CompartmentMgrVtbl
;
262 This
->pUnkOuter
= pUnkOuter
;
263 list_init(&This
->values
);
267 *ppOut
= (IUnknown
*)&This
->ITfCompartmentMgr_iface
;
268 TRACE("returning %p\n", *ppOut
);
274 hr
= ITfCompartmentMgr_QueryInterface(&This
->ITfCompartmentMgr_iface
, riid
, (void**)ppOut
);
276 HeapFree(GetProcessHeap(),0,This
);
281 /**************************************************
282 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
283 **************************************************/
284 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid
*This
)
286 TRACE("destroying %p\n", This
);
287 HeapFree(GetProcessHeap(),0,This
);
290 static HRESULT WINAPI
CompartmentEnumGuid_QueryInterface(IEnumGUID
*iface
, REFIID iid
, LPVOID
*ppvOut
)
292 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
295 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
297 *ppvOut
= &This
->IEnumGUID_iface
;
302 IEnumGUID_AddRef(iface
);
306 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
307 return E_NOINTERFACE
;
310 static ULONG WINAPI
CompartmentEnumGuid_AddRef(IEnumGUID
*iface
)
312 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
313 return InterlockedIncrement(&This
->refCount
);
316 static ULONG WINAPI
CompartmentEnumGuid_Release(IEnumGUID
*iface
)
318 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
321 ret
= InterlockedDecrement(&This
->refCount
);
323 CompartmentEnumGuid_Destructor(This
);
327 /*****************************************************
328 * IEnumGuid functions
329 *****************************************************/
330 static HRESULT WINAPI
CompartmentEnumGuid_Next(IEnumGUID
*iface
,
331 ULONG celt
, GUID
*rgelt
, ULONG
*pceltFetched
)
333 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
336 TRACE("(%p)\n",This
);
338 if (rgelt
== NULL
) return E_POINTER
;
340 while (fetched
< celt
&& This
->cursor
)
342 CompartmentValue
* value
= LIST_ENTRY(This
->cursor
,CompartmentValue
,entry
);
346 This
->cursor
= list_next(This
->values
,This
->cursor
);
347 *rgelt
= value
->guid
;
353 if (pceltFetched
) *pceltFetched
= fetched
;
354 return fetched
== celt
? S_OK
: S_FALSE
;
357 static HRESULT WINAPI
CompartmentEnumGuid_Skip(IEnumGUID
*iface
, ULONG celt
)
359 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
360 TRACE("(%p)\n",This
);
362 This
->cursor
= list_next(This
->values
,This
->cursor
);
366 static HRESULT WINAPI
CompartmentEnumGuid_Reset(IEnumGUID
*iface
)
368 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
369 TRACE("(%p)\n",This
);
370 This
->cursor
= list_head(This
->values
);
374 static HRESULT WINAPI
CompartmentEnumGuid_Clone(IEnumGUID
*iface
,
377 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
380 TRACE("(%p)\n",This
);
382 if (ppenum
== NULL
) return E_POINTER
;
384 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
387 CompartmentEnumGuid
*new_This
= impl_from_IEnumGUID(*ppenum
);
388 new_This
->cursor
= This
->cursor
;
393 static const IEnumGUIDVtbl EnumGUIDVtbl
=
395 CompartmentEnumGuid_QueryInterface
,
396 CompartmentEnumGuid_AddRef
,
397 CompartmentEnumGuid_Release
,
398 CompartmentEnumGuid_Next
,
399 CompartmentEnumGuid_Skip
,
400 CompartmentEnumGuid_Reset
,
401 CompartmentEnumGuid_Clone
404 static HRESULT
CompartmentEnumGuid_Constructor(struct list
*values
, IEnumGUID
**ppOut
)
406 CompartmentEnumGuid
*This
;
408 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentEnumGuid
));
410 return E_OUTOFMEMORY
;
412 This
->IEnumGUID_iface
.lpVtbl
= &EnumGUIDVtbl
;
415 This
->values
= values
;
416 This
->cursor
= list_head(values
);
418 *ppOut
= &This
->IEnumGUID_iface
;
419 TRACE("returning %p\n", *ppOut
);
423 /**************************************************
425 **************************************************/
426 static void free_sink(CompartmentSink
*sink
)
428 IUnknown_Release(sink
->interfaces
.pIUnknown
);
429 HeapFree(GetProcessHeap(),0,sink
);
432 static void Compartment_Destructor(Compartment
*This
)
434 struct list
*cursor
, *cursor2
;
435 TRACE("destroying %p\n", This
);
436 VariantClear(&This
->variant
);
437 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->CompartmentEventSink
)
439 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
443 HeapFree(GetProcessHeap(),0,This
);
446 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
448 Compartment
*This
= impl_from_ITfCompartment(iface
);
452 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartment
))
454 *ppvOut
= &This
->ITfCompartment_iface
;
456 else if (IsEqualIID(iid
, &IID_ITfSource
))
458 *ppvOut
= &This
->ITfSource_iface
;
463 ITfCompartment_AddRef(iface
);
467 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
468 return E_NOINTERFACE
;
471 static ULONG WINAPI
Compartment_AddRef(ITfCompartment
*iface
)
473 Compartment
*This
= impl_from_ITfCompartment(iface
);
474 return InterlockedIncrement(&This
->refCount
);
477 static ULONG WINAPI
Compartment_Release(ITfCompartment
*iface
)
479 Compartment
*This
= impl_from_ITfCompartment(iface
);
482 ret
= InterlockedDecrement(&This
->refCount
);
484 Compartment_Destructor(This
);
488 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
489 TfClientId tid
, const VARIANT
*pvarValue
)
491 Compartment
*This
= impl_from_ITfCompartment(iface
);
494 TRACE("(%p) %i %p\n",This
,tid
,pvarValue
);
499 if (!(V_VT(pvarValue
) == VT_BSTR
|| V_VT(pvarValue
) == VT_I4
||
500 V_VT(pvarValue
) == VT_UNKNOWN
))
503 if (!This
->valueData
->owner
)
504 This
->valueData
->owner
= tid
;
506 VariantClear(&This
->variant
);
508 /* Shallow copy of value and type */
509 This
->variant
= *pvarValue
;
511 if (V_VT(pvarValue
) == VT_BSTR
)
512 V_BSTR(&This
->variant
) = SysAllocStringByteLen((char*)V_BSTR(pvarValue
),
513 SysStringByteLen(V_BSTR(pvarValue
)));
514 else if (V_VT(pvarValue
) == VT_UNKNOWN
)
515 IUnknown_AddRef(V_UNKNOWN(&This
->variant
));
517 LIST_FOR_EACH(cursor
, &This
->CompartmentEventSink
)
519 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
520 ITfCompartmentEventSink_OnChange(sink
->interfaces
.pITfCompartmentEventSink
,&This
->valueData
->guid
);
526 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
529 Compartment
*This
= impl_from_ITfCompartment(iface
);
530 TRACE("(%p) %p\n",This
, pvarValue
);
535 VariantInit(pvarValue
);
536 if (V_VT(&This
->variant
) == VT_EMPTY
) return S_FALSE
;
537 return VariantCopy(pvarValue
,&This
->variant
);
540 static const ITfCompartmentVtbl CompartmentVtbl
=
542 Compartment_QueryInterface
,
545 Compartment_SetValue
,
549 /*****************************************************
550 * ITfSource functions
551 *****************************************************/
553 static HRESULT WINAPI
CompartmentSource_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
555 Compartment
*This
= impl_from_ITfSource(iface
);
556 return ITfCompartment_QueryInterface(&This
->ITfCompartment_iface
, iid
, ppvOut
);
559 static ULONG WINAPI
CompartmentSource_AddRef(ITfSource
*iface
)
561 Compartment
*This
= impl_from_ITfSource(iface
);
562 return ITfCompartment_AddRef(&This
->ITfCompartment_iface
);
565 static ULONG WINAPI
CompartmentSource_Release(ITfSource
*iface
)
567 Compartment
*This
= impl_from_ITfSource(iface
);
568 return ITfCompartment_Release(&This
->ITfCompartment_iface
);
571 static HRESULT WINAPI
CompartmentSource_AdviseSink(ITfSource
*iface
,
572 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
574 Compartment
*This
= impl_from_ITfSource(iface
);
577 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
579 if (!riid
|| !punk
|| !pdwCookie
)
582 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
584 cs
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink
));
586 return E_OUTOFMEMORY
;
587 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&cs
->interfaces
.pITfCompartmentEventSink
)))
589 HeapFree(GetProcessHeap(),0,cs
);
590 return CONNECT_E_CANNOTCONNECT
;
592 list_add_head(&This
->CompartmentEventSink
,&cs
->entry
);
593 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK
, cs
);
597 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
601 TRACE("cookie %x\n",*pdwCookie
);
606 static HRESULT WINAPI
CompartmentSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
608 Compartment
*This
= impl_from_ITfSource(iface
);
609 CompartmentSink
*sink
;
611 TRACE("(%p) %x\n",This
,pdwCookie
);
613 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_COMPARTMENTSINK
)
616 sink
= remove_Cookie(pdwCookie
);
618 return CONNECT_E_NOCONNECTION
;
620 list_remove(&sink
->entry
);
626 static const ITfSourceVtbl CompartmentSourceVtbl
=
628 CompartmentSource_QueryInterface
,
629 CompartmentSource_AddRef
,
630 CompartmentSource_Release
,
631 CompartmentSource_AdviseSink
,
632 CompartmentSource_UnadviseSink
,
635 static HRESULT
Compartment_Constructor(CompartmentValue
*valueData
, ITfCompartment
**ppOut
)
639 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
641 return E_OUTOFMEMORY
;
643 This
->ITfCompartment_iface
.lpVtbl
= &CompartmentVtbl
;
644 This
->ITfSource_iface
.lpVtbl
= &CompartmentSourceVtbl
;
647 This
->valueData
= valueData
;
648 VariantInit(&This
->variant
);
650 list_init(&This
->CompartmentEventSink
);
652 *ppOut
= &This
->ITfCompartment_iface
;
653 TRACE("returning %p\n", *ppOut
);