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 const ITfCompartmentMgrVtbl
*CompartmentMgrVtbl
;
41 typedef struct tagCompartmentEnumGuid
{
42 const IEnumGUIDVtbl
*Vtbl
;
47 } CompartmentEnumGuid
;
50 typedef struct tagCompartmentSink
{
54 ITfCompartmentEventSink
*pITfCompartmentEventSink
;
58 typedef struct tagCompartment
{
59 const ITfCompartmentVtbl
*Vtbl
;
60 const ITfSourceVtbl
*SourceVtbl
;
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 Compartment
*impl_from_ITfSourceVtbl(ITfSource
*iface
)
74 return (Compartment
*)((char *)iface
- FIELD_OFFSET(Compartment
,SourceVtbl
));
77 HRESULT
CompartmentMgr_Destructor(ITfCompartmentMgr
*iface
)
79 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
80 struct list
*cursor
, *cursor2
;
82 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->values
)
84 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
86 ITfCompartment_Release(value
->compartment
);
87 HeapFree(GetProcessHeap(),0,value
);
90 HeapFree(GetProcessHeap(),0,This
);
94 /*****************************************************
95 * ITfCompartmentMgr functions
96 *****************************************************/
97 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
99 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
101 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, *ppvOut
);
106 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
113 ITfCompartmentMgr_AddRef(iface
);
117 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
118 return E_NOINTERFACE
;
122 static ULONG WINAPI
CompartmentMgr_AddRef(ITfCompartmentMgr
*iface
)
124 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
126 return IUnknown_AddRef(This
->pUnkOuter
);
128 return InterlockedIncrement(&This
->refCount
);
131 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
133 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
135 return IUnknown_Release(This
->pUnkOuter
);
140 ret
= InterlockedDecrement(&This
->refCount
);
142 CompartmentMgr_Destructor(iface
);
147 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
148 REFGUID rguid
, ITfCompartment
**ppcomp
)
150 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
151 CompartmentValue
* value
;
155 TRACE("(%p) %s %p\n",This
,debugstr_guid(rguid
),ppcomp
);
157 LIST_FOR_EACH(cursor
, &This
->values
)
159 value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
160 if (IsEqualGUID(rguid
,&value
->guid
))
162 ITfCompartment_AddRef(value
->compartment
);
163 *ppcomp
= value
->compartment
;
168 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
169 value
->guid
= *rguid
;
171 hr
= Compartment_Constructor(value
,&value
->compartment
);
174 list_add_head(&This
->values
,&value
->entry
);
175 ITfCompartment_AddRef(value
->compartment
);
176 *ppcomp
= value
->compartment
;
180 HeapFree(GetProcessHeap(),0,value
);
186 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
187 TfClientId tid
, REFGUID rguid
)
190 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
191 TRACE("(%p) %i %s\n",This
,tid
,debugstr_guid(rguid
));
193 LIST_FOR_EACH(cursor
, &This
->values
)
195 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
196 if (IsEqualGUID(rguid
,&value
->guid
))
198 if (value
->owner
&& tid
!= value
->owner
)
201 ITfCompartment_Release(value
->compartment
);
202 HeapFree(GetProcessHeap(),0,value
);
207 return CONNECT_E_NOCONNECTION
;
210 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
213 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
214 TRACE("(%p) %p\n",This
,ppEnum
);
217 return CompartmentEnumGuid_Constructor(&This
->values
, ppEnum
);
220 static const ITfCompartmentMgrVtbl CompartmentMgr_CompartmentMgrVtbl
=
222 CompartmentMgr_QueryInterface
,
223 CompartmentMgr_AddRef
,
224 CompartmentMgr_Release
,
226 CompartmentMgr_GetCompartment
,
227 CompartmentMgr_ClearCompartment
,
228 CompartmentMgr_EnumCompartments
231 HRESULT
CompartmentMgr_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, IUnknown
**ppOut
)
233 CompartmentMgr
*This
;
238 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
239 return CLASS_E_NOAGGREGATION
;
241 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
243 return E_OUTOFMEMORY
;
245 This
->CompartmentMgrVtbl
= &CompartmentMgr_CompartmentMgrVtbl
;
246 This
->pUnkOuter
= pUnkOuter
;
247 list_init(&This
->values
);
251 TRACE("returning %p\n", This
);
252 *ppOut
= (IUnknown
*)This
;
258 hr
= IUnknown_QueryInterface((IUnknown
*)This
, riid
, (LPVOID
*)ppOut
);
260 HeapFree(GetProcessHeap(),0,This
);
265 /**************************************************
266 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
267 **************************************************/
268 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid
*This
)
270 TRACE("destroying %p\n", This
);
271 HeapFree(GetProcessHeap(),0,This
);
274 static HRESULT WINAPI
CompartmentEnumGuid_QueryInterface(IEnumGUID
*iface
, REFIID iid
, LPVOID
*ppvOut
)
276 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
279 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
286 IEnumGUID_AddRef(iface
);
290 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
291 return E_NOINTERFACE
;
294 static ULONG WINAPI
CompartmentEnumGuid_AddRef(IEnumGUID
*iface
)
296 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
297 return InterlockedIncrement(&This
->refCount
);
300 static ULONG WINAPI
CompartmentEnumGuid_Release(IEnumGUID
*iface
)
302 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
305 ret
= InterlockedDecrement(&This
->refCount
);
307 CompartmentEnumGuid_Destructor(This
);
311 /*****************************************************
312 * IEnumGuid functions
313 *****************************************************/
314 static HRESULT WINAPI
CompartmentEnumGuid_Next( LPENUMGUID iface
,
315 ULONG celt
, GUID
*rgelt
, ULONG
*pceltFetched
)
317 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
320 TRACE("(%p)\n",This
);
322 if (rgelt
== NULL
) return E_POINTER
;
324 while (fetched
< celt
&& This
->cursor
)
326 CompartmentValue
* value
= LIST_ENTRY(This
->cursor
,CompartmentValue
,entry
);
330 This
->cursor
= list_next(This
->values
,This
->cursor
);
331 *rgelt
= value
->guid
;
337 if (pceltFetched
) *pceltFetched
= fetched
;
338 return fetched
== celt
? S_OK
: S_FALSE
;
341 static HRESULT WINAPI
CompartmentEnumGuid_Skip( LPENUMGUID iface
, ULONG celt
)
343 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
344 TRACE("(%p)\n",This
);
346 This
->cursor
= list_next(This
->values
,This
->cursor
);
350 static HRESULT WINAPI
CompartmentEnumGuid_Reset( LPENUMGUID iface
)
352 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
353 TRACE("(%p)\n",This
);
354 This
->cursor
= list_head(This
->values
);
358 static HRESULT WINAPI
CompartmentEnumGuid_Clone( LPENUMGUID iface
,
361 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
364 TRACE("(%p)\n",This
);
366 if (ppenum
== NULL
) return E_POINTER
;
368 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
371 CompartmentEnumGuid
*new_This
= (CompartmentEnumGuid
*)*ppenum
;
372 new_This
->cursor
= This
->cursor
;
377 static const IEnumGUIDVtbl IEnumGUID_Vtbl
={
378 CompartmentEnumGuid_QueryInterface
,
379 CompartmentEnumGuid_AddRef
,
380 CompartmentEnumGuid_Release
,
382 CompartmentEnumGuid_Next
,
383 CompartmentEnumGuid_Skip
,
384 CompartmentEnumGuid_Reset
,
385 CompartmentEnumGuid_Clone
388 static HRESULT
CompartmentEnumGuid_Constructor(struct list
*values
, IEnumGUID
**ppOut
)
390 CompartmentEnumGuid
*This
;
392 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentEnumGuid
));
394 return E_OUTOFMEMORY
;
396 This
->Vtbl
= &IEnumGUID_Vtbl
;
399 This
->values
= values
;
400 This
->cursor
= list_head(values
);
402 TRACE("returning %p\n", This
);
403 *ppOut
= (IEnumGUID
*)This
;
407 /**************************************************
409 **************************************************/
410 static void free_sink(CompartmentSink
*sink
)
412 IUnknown_Release(sink
->interfaces
.pIUnknown
);
413 HeapFree(GetProcessHeap(),0,sink
);
416 static void Compartment_Destructor(Compartment
*This
)
418 struct list
*cursor
, *cursor2
;
419 TRACE("destroying %p\n", This
);
420 VariantClear(&This
->variant
);
421 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->CompartmentEventSink
)
423 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
427 HeapFree(GetProcessHeap(),0,This
);
430 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
432 Compartment
*This
= (Compartment
*)iface
;
435 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartment
))
439 else if (IsEqualIID(iid
, &IID_ITfSource
))
441 *ppvOut
= &This
->SourceVtbl
;
446 ITfCompartment_AddRef(iface
);
450 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
451 return E_NOINTERFACE
;
454 static ULONG WINAPI
Compartment_AddRef(ITfCompartment
*iface
)
456 Compartment
*This
= (Compartment
*)iface
;
457 return InterlockedIncrement(&This
->refCount
);
460 static ULONG WINAPI
Compartment_Release(ITfCompartment
*iface
)
462 Compartment
*This
= (Compartment
*)iface
;
465 ret
= InterlockedDecrement(&This
->refCount
);
467 Compartment_Destructor(This
);
471 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
472 TfClientId tid
, const VARIANT
*pvarValue
)
474 Compartment
*This
= (Compartment
*)iface
;
477 TRACE("(%p) %i %p\n",This
,tid
,pvarValue
);
482 if (!(V_VT(pvarValue
) == VT_BSTR
|| V_VT(pvarValue
) == VT_I4
||
483 V_VT(pvarValue
) == VT_UNKNOWN
))
486 if (!This
->valueData
->owner
)
487 This
->valueData
->owner
= tid
;
489 VariantClear(&This
->variant
);
491 /* Shallow copy of value and type */
492 This
->variant
= *pvarValue
;
494 if (V_VT(pvarValue
) == VT_BSTR
)
495 V_BSTR(&This
->variant
) = SysAllocStringByteLen((char*)V_BSTR(pvarValue
),
496 SysStringByteLen(V_BSTR(pvarValue
)));
497 else if (V_VT(pvarValue
) == VT_UNKNOWN
)
498 IUnknown_AddRef(V_UNKNOWN(&This
->variant
));
500 LIST_FOR_EACH(cursor
, &This
->CompartmentEventSink
)
502 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
503 ITfCompartmentEventSink_OnChange(sink
->interfaces
.pITfCompartmentEventSink
,&This
->valueData
->guid
);
509 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
512 Compartment
*This
= (Compartment
*)iface
;
513 TRACE("(%p) %p\n",This
, pvarValue
);
518 VariantInit(pvarValue
);
519 if (V_VT(&This
->variant
) == VT_EMPTY
) return S_FALSE
;
520 return VariantCopy(pvarValue
,&This
->variant
);
523 static const ITfCompartmentVtbl ITfCompartment_Vtbl
={
524 Compartment_QueryInterface
,
528 Compartment_SetValue
,
532 /*****************************************************
533 * ITfSource functions
534 *****************************************************/
536 static HRESULT WINAPI
Source_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
538 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
539 return Compartment_QueryInterface((ITfCompartment
*)This
, iid
, *ppvOut
);
542 static ULONG WINAPI
Source_AddRef(ITfSource
*iface
)
544 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
545 return Compartment_AddRef((ITfCompartment
*)This
);
548 static ULONG WINAPI
Source_Release(ITfSource
*iface
)
550 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
551 return Compartment_Release((ITfCompartment
*)This
);
554 static HRESULT WINAPI
CompartmentSource_AdviseSink(ITfSource
*iface
,
555 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
558 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
560 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
562 if (!riid
|| !punk
|| !pdwCookie
)
565 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
567 cs
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink
));
569 return E_OUTOFMEMORY
;
570 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&cs
->interfaces
.pITfCompartmentEventSink
)))
572 HeapFree(GetProcessHeap(),0,cs
);
573 return CONNECT_E_CANNOTCONNECT
;
575 list_add_head(&This
->CompartmentEventSink
,&cs
->entry
);
576 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK
, cs
);
580 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
584 TRACE("cookie %x\n",*pdwCookie
);
589 static HRESULT WINAPI
CompartmentSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
591 CompartmentSink
*sink
;
592 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
594 TRACE("(%p) %x\n",This
,pdwCookie
);
596 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_COMPARTMENTSINK
)
599 sink
= remove_Cookie(pdwCookie
);
601 return CONNECT_E_NOCONNECTION
;
603 list_remove(&sink
->entry
);
609 static const ITfSourceVtbl Compartment_SourceVtbl
=
611 Source_QueryInterface
,
615 CompartmentSource_AdviseSink
,
616 CompartmentSource_UnadviseSink
,
619 static HRESULT
Compartment_Constructor(CompartmentValue
*valueData
, ITfCompartment
**ppOut
)
623 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
625 return E_OUTOFMEMORY
;
627 This
->Vtbl
= &ITfCompartment_Vtbl
;
628 This
->SourceVtbl
= &Compartment_SourceVtbl
;
631 This
->valueData
= valueData
;
632 VariantInit(&This
->variant
);
634 list_init(&This
->CompartmentEventSink
);
636 TRACE("returning %p\n", This
);
637 *ppOut
= (ITfCompartment
*)This
;