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
27 #include "wine/debug.h"
38 #include "wine/unicode.h"
39 #include "wine/list.h"
42 #include "msctf_internal.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(msctf
);
46 typedef struct tagCompartmentValue
{
50 ITfCompartment
*compartment
;
53 typedef struct tagCompartmentMgr
{
54 ITfCompartmentMgr ITfCompartmentMgr_iface
;
62 typedef struct tagCompartmentEnumGuid
{
63 IEnumGUID IEnumGUID_iface
;
68 } CompartmentEnumGuid
;
71 typedef struct tagCompartmentSink
{
75 ITfCompartmentEventSink
*pITfCompartmentEventSink
;
79 typedef struct tagCompartment
{
80 ITfCompartment ITfCompartment_iface
;
81 ITfSource ITfSource_iface
;
84 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
86 CompartmentValue
*valueData
;
87 struct list CompartmentEventSink
;
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
);
122 ITfCompartment_Release(value
->compartment
);
123 HeapFree(GetProcessHeap(),0,value
);
126 HeapFree(GetProcessHeap(),0,This
);
130 /*****************************************************
131 * ITfCompartmentMgr functions
132 *****************************************************/
133 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
135 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
137 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, ppvOut
);
142 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
144 *ppvOut
= &This
->ITfCompartmentMgr_iface
;
149 ITfCompartmentMgr_AddRef(iface
);
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
);
162 return IUnknown_AddRef(This
->pUnkOuter
);
164 return InterlockedIncrement(&This
->refCount
);
167 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
169 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
171 return IUnknown_Release(This
->pUnkOuter
);
176 ret
= InterlockedDecrement(&This
->refCount
);
178 CompartmentMgr_Destructor(iface
);
183 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
184 REFGUID rguid
, ITfCompartment
**ppcomp
)
186 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
187 CompartmentValue
* value
;
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
;
204 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
205 value
->guid
= *rguid
;
207 hr
= Compartment_Constructor(value
,&value
->compartment
);
210 list_add_head(&This
->values
,&value
->entry
);
211 ITfCompartment_AddRef(value
->compartment
);
212 *ppcomp
= value
->compartment
;
216 HeapFree(GetProcessHeap(),0,value
);
222 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
223 TfClientId tid
, REFGUID rguid
)
225 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
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
)
238 ITfCompartment_Release(value
->compartment
);
239 HeapFree(GetProcessHeap(),0,value
);
244 return CONNECT_E_NOCONNECTION
;
247 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
250 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
252 TRACE("(%p) %p\n",This
,ppEnum
);
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
;
275 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
276 return CLASS_E_NOAGGREGATION
;
278 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
280 return E_OUTOFMEMORY
;
282 This
->ITfCompartmentMgr_iface
.lpVtbl
= &CompartmentMgrVtbl
;
283 This
->pUnkOuter
= pUnkOuter
;
284 list_init(&This
->values
);
288 *ppOut
= (IUnknown
*)&This
->ITfCompartmentMgr_iface
;
289 TRACE("returning %p\n", *ppOut
);
295 hr
= ITfCompartmentMgr_QueryInterface(&This
->ITfCompartmentMgr_iface
, riid
, (void**)ppOut
);
297 HeapFree(GetProcessHeap(),0,This
);
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
);
316 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
318 *ppvOut
= &This
->IEnumGUID_iface
;
323 IEnumGUID_AddRef(iface
);
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
);
342 ret
= InterlockedDecrement(&This
->refCount
);
344 CompartmentEnumGuid_Destructor(This
);
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
);
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
);
367 This
->cursor
= list_next(This
->values
,This
->cursor
);
368 *rgelt
= value
->guid
;
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
);
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
);
395 static HRESULT WINAPI
CompartmentEnumGuid_Clone(IEnumGUID
*iface
,
398 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
401 TRACE("(%p)\n",This
);
403 if (ppenum
== NULL
) return E_POINTER
;
405 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
408 CompartmentEnumGuid
*new_This
= impl_from_IEnumGUID(*ppenum
);
409 new_This
->cursor
= This
->cursor
;
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
));
431 return E_OUTOFMEMORY
;
433 This
->IEnumGUID_iface
.lpVtbl
= &EnumGUIDVtbl
;
436 This
->values
= values
;
437 This
->cursor
= list_head(values
);
439 *ppOut
= &This
->IEnumGUID_iface
;
440 TRACE("returning %p\n", *ppOut
);
444 /**************************************************
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
);
464 HeapFree(GetProcessHeap(),0,This
);
467 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
469 Compartment
*This
= impl_from_ITfCompartment(iface
);
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
;
484 ITfCompartment_AddRef(iface
);
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
);
503 ret
= InterlockedDecrement(&This
->refCount
);
505 Compartment_Destructor(This
);
509 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
510 TfClientId tid
, const VARIANT
*pvarValue
)
512 Compartment
*This
= impl_from_ITfCompartment(iface
);
515 TRACE("(%p) %i %p\n",This
,tid
,pvarValue
);
520 if (!(V_VT(pvarValue
) == VT_BSTR
|| V_VT(pvarValue
) == VT_I4
||
521 V_VT(pvarValue
) == VT_UNKNOWN
))
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
);
547 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
550 Compartment
*This
= impl_from_ITfCompartment(iface
);
551 TRACE("(%p) %p\n",This
, pvarValue
);
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
,
566 Compartment_SetValue
,
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
);
598 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
600 if (!riid
|| !punk
|| !pdwCookie
)
603 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
605 cs
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink
));
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
);
618 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
622 TRACE("cookie %x\n",*pdwCookie
);
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
)
637 sink
= remove_Cookie(pdwCookie
);
639 return CONNECT_E_NOCONNECTION
;
641 list_remove(&sink
->entry
);
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
)
660 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
662 return E_OUTOFMEMORY
;
664 This
->ITfCompartment_iface
.lpVtbl
= &CompartmentVtbl
;
665 This
->ITfSource_iface
.lpVtbl
= &CompartmentSourceVtbl
;
668 This
->valueData
= valueData
;
669 VariantInit(&This
->variant
);
671 list_init(&This
->CompartmentEventSink
);
673 *ppOut
= &This
->ITfCompartment_iface
;
674 TRACE("returning %p\n", *ppOut
);