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
25 #include "wine/debug.h"
37 #include "msctf_internal.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msctf
);
41 typedef struct tagCompartmentValue
{
45 ITfCompartment
*compartment
;
48 typedef struct tagCompartmentMgr
{
49 ITfCompartmentMgr ITfCompartmentMgr_iface
;
57 typedef struct tagCompartmentEnumGuid
{
58 IEnumGUID IEnumGUID_iface
;
63 } CompartmentEnumGuid
;
65 typedef struct tagCompartment
{
66 ITfCompartment ITfCompartment_iface
;
67 ITfSource ITfSource_iface
;
70 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
72 CompartmentValue
*valueData
;
73 struct list CompartmentEventSink
;
76 static HRESULT
CompartmentEnumGuid_Constructor(struct list
* values
, IEnumGUID
**ppOut
);
77 static HRESULT
Compartment_Constructor(CompartmentValue
*value
, ITfCompartment
**ppOut
);
79 static inline CompartmentMgr
*impl_from_ITfCompartmentMgr(ITfCompartmentMgr
*iface
)
81 return CONTAINING_RECORD(iface
, CompartmentMgr
, ITfCompartmentMgr_iface
);
84 static inline Compartment
*impl_from_ITfCompartment(ITfCompartment
*iface
)
86 return CONTAINING_RECORD(iface
, Compartment
, ITfCompartment_iface
);
89 static inline Compartment
*impl_from_ITfSource(ITfSource
*iface
)
91 return CONTAINING_RECORD(iface
, Compartment
, ITfSource_iface
);
94 static inline CompartmentEnumGuid
*impl_from_IEnumGUID(IEnumGUID
*iface
)
96 return CONTAINING_RECORD(iface
, CompartmentEnumGuid
, IEnumGUID_iface
);
99 HRESULT
CompartmentMgr_Destructor(ITfCompartmentMgr
*iface
)
101 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
102 struct list
*cursor
, *cursor2
;
104 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->values
)
106 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
108 ITfCompartment_Release(value
->compartment
);
109 HeapFree(GetProcessHeap(),0,value
);
112 HeapFree(GetProcessHeap(),0,This
);
116 /*****************************************************
117 * ITfCompartmentMgr functions
118 *****************************************************/
119 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
121 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
123 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, ppvOut
);
128 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
130 *ppvOut
= &This
->ITfCompartmentMgr_iface
;
135 ITfCompartmentMgr_AddRef(iface
);
139 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
140 return E_NOINTERFACE
;
144 static ULONG WINAPI
CompartmentMgr_AddRef(ITfCompartmentMgr
*iface
)
146 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
148 return IUnknown_AddRef(This
->pUnkOuter
);
150 return InterlockedIncrement(&This
->refCount
);
153 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
155 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
157 return IUnknown_Release(This
->pUnkOuter
);
162 ret
= InterlockedDecrement(&This
->refCount
);
164 CompartmentMgr_Destructor(iface
);
169 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
170 REFGUID rguid
, ITfCompartment
**ppcomp
)
172 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
173 CompartmentValue
* value
;
177 TRACE("(%p) %s %p\n",This
,debugstr_guid(rguid
),ppcomp
);
179 LIST_FOR_EACH(cursor
, &This
->values
)
181 value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
182 if (IsEqualGUID(rguid
,&value
->guid
))
184 ITfCompartment_AddRef(value
->compartment
);
185 *ppcomp
= value
->compartment
;
190 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
191 value
->guid
= *rguid
;
193 hr
= Compartment_Constructor(value
,&value
->compartment
);
196 list_add_head(&This
->values
,&value
->entry
);
197 ITfCompartment_AddRef(value
->compartment
);
198 *ppcomp
= value
->compartment
;
202 HeapFree(GetProcessHeap(),0,value
);
208 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
209 TfClientId tid
, REFGUID rguid
)
211 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
214 TRACE("(%p) %li %s\n",This
,tid
,debugstr_guid(rguid
));
216 LIST_FOR_EACH(cursor
, &This
->values
)
218 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
219 if (IsEqualGUID(rguid
,&value
->guid
))
221 if (value
->owner
&& tid
!= value
->owner
)
224 ITfCompartment_Release(value
->compartment
);
225 HeapFree(GetProcessHeap(),0,value
);
230 return CONNECT_E_NOCONNECTION
;
233 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
236 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
238 TRACE("(%p) %p\n",This
,ppEnum
);
241 return CompartmentEnumGuid_Constructor(&This
->values
, ppEnum
);
244 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl
=
246 CompartmentMgr_QueryInterface
,
247 CompartmentMgr_AddRef
,
248 CompartmentMgr_Release
,
249 CompartmentMgr_GetCompartment
,
250 CompartmentMgr_ClearCompartment
,
251 CompartmentMgr_EnumCompartments
254 HRESULT
CompartmentMgr_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, IUnknown
**ppOut
)
256 CompartmentMgr
*This
;
261 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
262 return CLASS_E_NOAGGREGATION
;
264 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
266 return E_OUTOFMEMORY
;
268 This
->ITfCompartmentMgr_iface
.lpVtbl
= &CompartmentMgrVtbl
;
269 This
->pUnkOuter
= pUnkOuter
;
270 list_init(&This
->values
);
274 *ppOut
= (IUnknown
*)&This
->ITfCompartmentMgr_iface
;
275 TRACE("returning %p\n", *ppOut
);
281 hr
= ITfCompartmentMgr_QueryInterface(&This
->ITfCompartmentMgr_iface
, riid
, (void**)ppOut
);
283 HeapFree(GetProcessHeap(),0,This
);
288 /**************************************************
289 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
290 **************************************************/
291 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid
*This
)
293 TRACE("destroying %p\n", This
);
294 HeapFree(GetProcessHeap(),0,This
);
297 static HRESULT WINAPI
CompartmentEnumGuid_QueryInterface(IEnumGUID
*iface
, REFIID iid
, LPVOID
*ppvOut
)
299 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
302 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
304 *ppvOut
= &This
->IEnumGUID_iface
;
309 IEnumGUID_AddRef(iface
);
313 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
314 return E_NOINTERFACE
;
317 static ULONG WINAPI
CompartmentEnumGuid_AddRef(IEnumGUID
*iface
)
319 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
320 return InterlockedIncrement(&This
->refCount
);
323 static ULONG WINAPI
CompartmentEnumGuid_Release(IEnumGUID
*iface
)
325 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
328 ret
= InterlockedDecrement(&This
->refCount
);
330 CompartmentEnumGuid_Destructor(This
);
334 /*****************************************************
335 * IEnumGuid functions
336 *****************************************************/
337 static HRESULT WINAPI
CompartmentEnumGuid_Next(IEnumGUID
*iface
,
338 ULONG celt
, GUID
*rgelt
, ULONG
*pceltFetched
)
340 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
343 TRACE("(%p)\n",This
);
345 if (rgelt
== NULL
) return E_POINTER
;
347 while (fetched
< celt
&& This
->cursor
)
349 CompartmentValue
* value
= LIST_ENTRY(This
->cursor
,CompartmentValue
,entry
);
353 This
->cursor
= list_next(This
->values
,This
->cursor
);
354 *rgelt
= value
->guid
;
360 if (pceltFetched
) *pceltFetched
= fetched
;
361 return fetched
== celt
? S_OK
: S_FALSE
;
364 static HRESULT WINAPI
CompartmentEnumGuid_Skip(IEnumGUID
*iface
, ULONG celt
)
366 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
367 TRACE("(%p)\n",This
);
369 This
->cursor
= list_next(This
->values
,This
->cursor
);
373 static HRESULT WINAPI
CompartmentEnumGuid_Reset(IEnumGUID
*iface
)
375 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
376 TRACE("(%p)\n",This
);
377 This
->cursor
= list_head(This
->values
);
381 static HRESULT WINAPI
CompartmentEnumGuid_Clone(IEnumGUID
*iface
,
384 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
387 TRACE("(%p)\n",This
);
389 if (ppenum
== NULL
) return E_POINTER
;
391 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
394 CompartmentEnumGuid
*new_This
= impl_from_IEnumGUID(*ppenum
);
395 new_This
->cursor
= This
->cursor
;
400 static const IEnumGUIDVtbl EnumGUIDVtbl
=
402 CompartmentEnumGuid_QueryInterface
,
403 CompartmentEnumGuid_AddRef
,
404 CompartmentEnumGuid_Release
,
405 CompartmentEnumGuid_Next
,
406 CompartmentEnumGuid_Skip
,
407 CompartmentEnumGuid_Reset
,
408 CompartmentEnumGuid_Clone
411 static HRESULT
CompartmentEnumGuid_Constructor(struct list
*values
, IEnumGUID
**ppOut
)
413 CompartmentEnumGuid
*This
;
415 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentEnumGuid
));
417 return E_OUTOFMEMORY
;
419 This
->IEnumGUID_iface
.lpVtbl
= &EnumGUIDVtbl
;
422 This
->values
= values
;
423 This
->cursor
= list_head(values
);
425 *ppOut
= &This
->IEnumGUID_iface
;
426 TRACE("returning %p\n", *ppOut
);
430 /**************************************************
432 **************************************************/
433 static void Compartment_Destructor(Compartment
*This
)
435 TRACE("destroying %p\n", This
);
436 VariantClear(&This
->variant
);
437 free_sinks(&This
->CompartmentEventSink
);
438 HeapFree(GetProcessHeap(),0,This
);
441 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
443 Compartment
*This
= impl_from_ITfCompartment(iface
);
447 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartment
))
449 *ppvOut
= &This
->ITfCompartment_iface
;
451 else if (IsEqualIID(iid
, &IID_ITfSource
))
453 *ppvOut
= &This
->ITfSource_iface
;
458 ITfCompartment_AddRef(iface
);
462 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
463 return E_NOINTERFACE
;
466 static ULONG WINAPI
Compartment_AddRef(ITfCompartment
*iface
)
468 Compartment
*This
= impl_from_ITfCompartment(iface
);
469 return InterlockedIncrement(&This
->refCount
);
472 static ULONG WINAPI
Compartment_Release(ITfCompartment
*iface
)
474 Compartment
*This
= impl_from_ITfCompartment(iface
);
477 ret
= InterlockedDecrement(&This
->refCount
);
479 Compartment_Destructor(This
);
483 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
484 TfClientId tid
, const VARIANT
*pvarValue
)
486 Compartment
*This
= impl_from_ITfCompartment(iface
);
487 ITfCompartmentEventSink
*sink
;
490 TRACE("(%p) %li %p\n",This
,tid
,pvarValue
);
495 if (!(V_VT(pvarValue
) == VT_BSTR
|| V_VT(pvarValue
) == VT_I4
||
496 V_VT(pvarValue
) == VT_UNKNOWN
))
499 if (!This
->valueData
->owner
)
500 This
->valueData
->owner
= tid
;
502 VariantClear(&This
->variant
);
504 /* Shallow copy of value and type */
505 This
->variant
= *pvarValue
;
507 if (V_VT(pvarValue
) == VT_BSTR
)
508 V_BSTR(&This
->variant
) = SysAllocStringByteLen((char*)V_BSTR(pvarValue
),
509 SysStringByteLen(V_BSTR(pvarValue
)));
510 else if (V_VT(pvarValue
) == VT_UNKNOWN
)
511 IUnknown_AddRef(V_UNKNOWN(&This
->variant
));
513 SINK_FOR_EACH(cursor
, &This
->CompartmentEventSink
, ITfCompartmentEventSink
, sink
)
515 ITfCompartmentEventSink_OnChange(sink
, &This
->valueData
->guid
);
521 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
524 Compartment
*This
= impl_from_ITfCompartment(iface
);
525 TRACE("(%p) %p\n",This
, pvarValue
);
530 VariantInit(pvarValue
);
531 if (V_VT(&This
->variant
) == VT_EMPTY
) return S_FALSE
;
532 return VariantCopy(pvarValue
,&This
->variant
);
535 static const ITfCompartmentVtbl CompartmentVtbl
=
537 Compartment_QueryInterface
,
540 Compartment_SetValue
,
544 /*****************************************************
545 * ITfSource functions
546 *****************************************************/
548 static HRESULT WINAPI
CompartmentSource_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
550 Compartment
*This
= impl_from_ITfSource(iface
);
551 return ITfCompartment_QueryInterface(&This
->ITfCompartment_iface
, iid
, ppvOut
);
554 static ULONG WINAPI
CompartmentSource_AddRef(ITfSource
*iface
)
556 Compartment
*This
= impl_from_ITfSource(iface
);
557 return ITfCompartment_AddRef(&This
->ITfCompartment_iface
);
560 static ULONG WINAPI
CompartmentSource_Release(ITfSource
*iface
)
562 Compartment
*This
= impl_from_ITfSource(iface
);
563 return ITfCompartment_Release(&This
->ITfCompartment_iface
);
566 static HRESULT WINAPI
CompartmentSource_AdviseSink(ITfSource
*iface
,
567 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
569 Compartment
*This
= impl_from_ITfSource(iface
);
571 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
573 if (!riid
|| !punk
|| !pdwCookie
)
576 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
577 return advise_sink(&This
->CompartmentEventSink
, &IID_ITfCompartmentEventSink
,
578 COOKIE_MAGIC_COMPARTMENTSINK
, punk
, pdwCookie
);
580 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
584 static HRESULT WINAPI
CompartmentSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
586 Compartment
*This
= impl_from_ITfSource(iface
);
588 TRACE("(%p) %lx\n",This
,pdwCookie
);
590 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_COMPARTMENTSINK
)
593 return unadvise_sink(pdwCookie
);
596 static const ITfSourceVtbl CompartmentSourceVtbl
=
598 CompartmentSource_QueryInterface
,
599 CompartmentSource_AddRef
,
600 CompartmentSource_Release
,
601 CompartmentSource_AdviseSink
,
602 CompartmentSource_UnadviseSink
,
605 static HRESULT
Compartment_Constructor(CompartmentValue
*valueData
, ITfCompartment
**ppOut
)
609 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
611 return E_OUTOFMEMORY
;
613 This
->ITfCompartment_iface
.lpVtbl
= &CompartmentVtbl
;
614 This
->ITfSource_iface
.lpVtbl
= &CompartmentSourceVtbl
;
617 This
->valueData
= valueData
;
618 VariantInit(&This
->variant
);
620 list_init(&This
->CompartmentEventSink
);
622 *ppOut
= &This
->ITfCompartment_iface
;
623 TRACE("returning %p\n", *ppOut
);