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 const ITfCompartmentMgrVtbl
*CompartmentMgrVtbl
;
62 typedef struct tagCompartmentEnumGuid
{
63 const IEnumGUIDVtbl
*Vtbl
;
68 } CompartmentEnumGuid
;
71 typedef struct tagCompartmentSink
{
75 ITfCompartmentEventSink
*pITfCompartmentEventSink
;
79 typedef struct tagCompartment
{
80 const ITfCompartmentVtbl
*Vtbl
;
81 const ITfSourceVtbl
*SourceVtbl
;
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 Compartment
*impl_from_ITfSourceVtbl(ITfSource
*iface
)
95 return (Compartment
*)((char *)iface
- FIELD_OFFSET(Compartment
,SourceVtbl
));
98 HRESULT
CompartmentMgr_Destructor(ITfCompartmentMgr
*iface
)
100 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
101 struct list
*cursor
, *cursor2
;
103 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->values
)
105 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
107 ITfCompartment_Release(value
->compartment
);
108 HeapFree(GetProcessHeap(),0,value
);
111 HeapFree(GetProcessHeap(),0,This
);
115 /*****************************************************
116 * ITfCompartmentMgr functions
117 *****************************************************/
118 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
120 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
122 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, *ppvOut
);
127 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
134 IUnknown_AddRef(iface
);
138 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
139 return E_NOINTERFACE
;
143 static ULONG WINAPI
CompartmentMgr_AddRef(ITfCompartmentMgr
*iface
)
145 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
147 return IUnknown_AddRef(This
->pUnkOuter
);
149 return InterlockedIncrement(&This
->refCount
);
152 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
154 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
156 return IUnknown_Release(This
->pUnkOuter
);
161 ret
= InterlockedDecrement(&This
->refCount
);
163 CompartmentMgr_Destructor(iface
);
168 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
169 REFGUID rguid
, ITfCompartment
**ppcomp
)
171 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
172 CompartmentValue
* value
;
176 TRACE("(%p) %s %p\n",This
,debugstr_guid(rguid
),ppcomp
);
178 LIST_FOR_EACH(cursor
, &This
->values
)
180 value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
181 if (IsEqualGUID(rguid
,&value
->guid
))
183 ITfCompartment_AddRef(value
->compartment
);
184 *ppcomp
= value
->compartment
;
189 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
190 value
->guid
= *rguid
;
192 hr
= Compartment_Constructor(value
,&value
->compartment
);
195 list_add_head(&This
->values
,&value
->entry
);
196 ITfCompartment_AddRef(value
->compartment
);
197 *ppcomp
= value
->compartment
;
201 HeapFree(GetProcessHeap(),0,value
);
207 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
208 TfClientId tid
, REFGUID rguid
)
211 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
212 TRACE("(%p) %i %s\n",This
,tid
,debugstr_guid(rguid
));
214 LIST_FOR_EACH(cursor
, &This
->values
)
216 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
217 if (IsEqualGUID(rguid
,&value
->guid
))
219 if (value
->owner
&& tid
!= value
->owner
)
222 ITfCompartment_Release(value
->compartment
);
223 HeapFree(GetProcessHeap(),0,value
);
228 return CONNECT_E_NOCONNECTION
;
231 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
234 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
235 TRACE("(%p) %p\n",This
,ppEnum
);
238 return CompartmentEnumGuid_Constructor(&This
->values
, ppEnum
);
241 static const ITfCompartmentMgrVtbl CompartmentMgr_CompartmentMgrVtbl
=
243 CompartmentMgr_QueryInterface
,
244 CompartmentMgr_AddRef
,
245 CompartmentMgr_Release
,
247 CompartmentMgr_GetCompartment
,
248 CompartmentMgr_ClearCompartment
,
249 CompartmentMgr_EnumCompartments
252 HRESULT
CompartmentMgr_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, IUnknown
**ppOut
)
254 CompartmentMgr
*This
;
259 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
260 return CLASS_E_NOAGGREGATION
;
262 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
264 return E_OUTOFMEMORY
;
266 This
->CompartmentMgrVtbl
= &CompartmentMgr_CompartmentMgrVtbl
;
267 This
->pUnkOuter
= pUnkOuter
;
268 list_init(&This
->values
);
272 TRACE("returning %p\n", This
);
273 *ppOut
= (IUnknown
*)This
;
279 hr
= IUnknown_QueryInterface((IUnknown
*)This
, riid
, (LPVOID
*)ppOut
);
281 HeapFree(GetProcessHeap(),0,This
);
286 /**************************************************
287 * IEnumGUID implementaion for ITfCompartmentMgr::EnumCompartments
288 **************************************************/
289 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid
*This
)
291 TRACE("destroying %p\n", This
);
292 HeapFree(GetProcessHeap(),0,This
);
295 static HRESULT WINAPI
CompartmentEnumGuid_QueryInterface(IEnumGUID
*iface
, REFIID iid
, LPVOID
*ppvOut
)
297 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
300 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
307 IUnknown_AddRef(iface
);
311 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
312 return E_NOINTERFACE
;
315 static ULONG WINAPI
CompartmentEnumGuid_AddRef(IEnumGUID
*iface
)
317 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
318 return InterlockedIncrement(&This
->refCount
);
321 static ULONG WINAPI
CompartmentEnumGuid_Release(IEnumGUID
*iface
)
323 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
326 ret
= InterlockedDecrement(&This
->refCount
);
328 CompartmentEnumGuid_Destructor(This
);
332 /*****************************************************
333 * IEnumGuid functions
334 *****************************************************/
335 static HRESULT WINAPI
CompartmentEnumGuid_Next( LPENUMGUID iface
,
336 ULONG celt
, GUID
*rgelt
, ULONG
*pceltFetched
)
338 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
341 TRACE("(%p)\n",This
);
343 if (rgelt
== NULL
) return E_POINTER
;
345 while (fetched
< celt
&& This
->cursor
)
347 CompartmentValue
* value
= LIST_ENTRY(This
->cursor
,CompartmentValue
,entry
);
351 This
->cursor
= list_next(This
->values
,This
->cursor
);
352 *rgelt
= value
->guid
;
358 if (pceltFetched
) *pceltFetched
= fetched
;
359 return fetched
== celt
? S_OK
: S_FALSE
;
362 static HRESULT WINAPI
CompartmentEnumGuid_Skip( LPENUMGUID iface
, ULONG celt
)
364 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
365 TRACE("(%p)\n",This
);
367 This
->cursor
= list_next(This
->values
,This
->cursor
);
371 static HRESULT WINAPI
CompartmentEnumGuid_Reset( LPENUMGUID iface
)
373 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
374 TRACE("(%p)\n",This
);
375 This
->cursor
= list_head(This
->values
);
379 static HRESULT WINAPI
CompartmentEnumGuid_Clone( LPENUMGUID iface
,
382 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
385 TRACE("(%p)\n",This
);
387 if (ppenum
== NULL
) return E_POINTER
;
389 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
392 CompartmentEnumGuid
*new_This
= (CompartmentEnumGuid
*)*ppenum
;
393 new_This
->cursor
= This
->cursor
;
398 static const IEnumGUIDVtbl IEnumGUID_Vtbl
={
399 CompartmentEnumGuid_QueryInterface
,
400 CompartmentEnumGuid_AddRef
,
401 CompartmentEnumGuid_Release
,
403 CompartmentEnumGuid_Next
,
404 CompartmentEnumGuid_Skip
,
405 CompartmentEnumGuid_Reset
,
406 CompartmentEnumGuid_Clone
409 static HRESULT
CompartmentEnumGuid_Constructor(struct list
*values
, IEnumGUID
**ppOut
)
411 CompartmentEnumGuid
*This
;
413 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentEnumGuid
));
415 return E_OUTOFMEMORY
;
417 This
->Vtbl
= &IEnumGUID_Vtbl
;
420 This
->values
= values
;
421 This
->cursor
= list_head(values
);
423 TRACE("returning %p\n", This
);
424 *ppOut
= (IEnumGUID
*)This
;
428 /**************************************************
430 **************************************************/
431 static void free_sink(CompartmentSink
*sink
)
433 IUnknown_Release(sink
->interfaces
.pIUnknown
);
434 HeapFree(GetProcessHeap(),0,sink
);
437 static void Compartment_Destructor(Compartment
*This
)
439 struct list
*cursor
, *cursor2
;
440 TRACE("destroying %p\n", This
);
441 VariantClear(&This
->variant
);
442 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->CompartmentEventSink
)
444 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
448 HeapFree(GetProcessHeap(),0,This
);
451 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
453 Compartment
*This
= (Compartment
*)iface
;
456 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartment
))
460 else if (IsEqualIID(iid
, &IID_ITfSource
))
462 *ppvOut
= &This
->SourceVtbl
;
467 IUnknown_AddRef(iface
);
471 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
472 return E_NOINTERFACE
;
475 static ULONG WINAPI
Compartment_AddRef(ITfCompartment
*iface
)
477 Compartment
*This
= (Compartment
*)iface
;
478 return InterlockedIncrement(&This
->refCount
);
481 static ULONG WINAPI
Compartment_Release(ITfCompartment
*iface
)
483 Compartment
*This
= (Compartment
*)iface
;
486 ret
= InterlockedDecrement(&This
->refCount
);
488 Compartment_Destructor(This
);
492 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
493 TfClientId tid
, const VARIANT
*pvarValue
)
495 Compartment
*This
= (Compartment
*)iface
;
498 TRACE("(%p) %i %p\n",This
,tid
,pvarValue
);
503 if (!(V_VT(pvarValue
) == VT_BSTR
|| V_VT(pvarValue
) == VT_I4
||
504 V_VT(pvarValue
) == VT_UNKNOWN
))
507 if (!This
->valueData
->owner
)
508 This
->valueData
->owner
= tid
;
510 VariantClear(&This
->variant
);
512 /* Shallow copy of value and type */
513 This
->variant
= *pvarValue
;
515 if (V_VT(pvarValue
) == VT_BSTR
)
516 V_BSTR(&This
->variant
) = SysAllocStringByteLen((char*)V_BSTR(pvarValue
),
517 SysStringByteLen(V_BSTR(pvarValue
)));
518 else if (V_VT(pvarValue
) == VT_UNKNOWN
)
519 IUnknown_AddRef(V_UNKNOWN(&This
->variant
));
521 LIST_FOR_EACH(cursor
, &This
->CompartmentEventSink
)
523 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
524 ITfCompartmentEventSink_OnChange(sink
->interfaces
.pITfCompartmentEventSink
,&This
->valueData
->guid
);
530 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
534 Compartment
*This
= (Compartment
*)iface
;
535 TRACE("(%p) %p\n",This
, pvarValue
);
540 pvarValue
->n1
.n2
.vt
= VT_EMPTY
;
541 if (!This
->variant
.n1
.n2
.vt
== VT_EMPTY
)
542 hr
= VariantCopy(pvarValue
,&This
->variant
);
546 static const ITfCompartmentVtbl ITfCompartment_Vtbl
={
547 Compartment_QueryInterface
,
551 Compartment_SetValue
,
555 /*****************************************************
556 * ITfSource functions
557 *****************************************************/
559 static HRESULT WINAPI
Source_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
561 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
562 return Compartment_QueryInterface((ITfCompartment
*)This
, iid
, *ppvOut
);
565 static ULONG WINAPI
Source_AddRef(ITfSource
*iface
)
567 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
568 return Compartment_AddRef((ITfCompartment
*)This
);
571 static ULONG WINAPI
Source_Release(ITfSource
*iface
)
573 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
574 return Compartment_Release((ITfCompartment
*)This
);
577 static WINAPI HRESULT
CompartmentSource_AdviseSink(ITfSource
*iface
,
578 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
581 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
583 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
585 if (!riid
|| !punk
|| !pdwCookie
)
588 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
590 cs
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink
));
592 return E_OUTOFMEMORY
;
593 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&cs
->interfaces
.pITfCompartmentEventSink
)))
595 HeapFree(GetProcessHeap(),0,cs
);
596 return CONNECT_E_CANNOTCONNECT
;
598 list_add_head(&This
->CompartmentEventSink
,&cs
->entry
);
599 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK
, cs
);
603 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
607 TRACE("cookie %x\n",*pdwCookie
);
612 static WINAPI HRESULT
CompartmentSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
614 CompartmentSink
*sink
;
615 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
617 TRACE("(%p) %x\n",This
,pdwCookie
);
619 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_COMPARTMENTSINK
)
622 sink
= (CompartmentSink
*)remove_Cookie(pdwCookie
);
624 return CONNECT_E_NOCONNECTION
;
626 list_remove(&sink
->entry
);
632 static const ITfSourceVtbl Compartment_SourceVtbl
=
634 Source_QueryInterface
,
638 CompartmentSource_AdviseSink
,
639 CompartmentSource_UnadviseSink
,
642 static HRESULT
Compartment_Constructor(CompartmentValue
*valueData
, ITfCompartment
**ppOut
)
646 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
648 return E_OUTOFMEMORY
;
650 This
->Vtbl
= &ITfCompartment_Vtbl
;
651 This
->SourceVtbl
= &Compartment_SourceVtbl
;
654 This
->valueData
= valueData
;
655 VariantInit(&This
->variant
);
657 list_init(&This
->CompartmentEventSink
);
659 TRACE("returning %p\n", This
);
660 *ppOut
= (ITfCompartment
*)This
;