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"
41 #include "msctf_internal.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf
);
45 typedef struct tagCompartmentValue
{
49 ITfCompartment
*compartment
;
52 typedef struct tagCompartmentMgr
{
53 ITfCompartmentMgr ITfCompartmentMgr_iface
;
61 typedef struct tagCompartmentEnumGuid
{
62 IEnumGUID IEnumGUID_iface
;
67 } CompartmentEnumGuid
;
69 typedef struct tagCompartment
{
70 ITfCompartment ITfCompartment_iface
;
71 ITfSource ITfSource_iface
;
74 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
76 CompartmentValue
*valueData
;
77 struct list CompartmentEventSink
;
80 static HRESULT
CompartmentEnumGuid_Constructor(struct list
* values
, IEnumGUID
**ppOut
);
81 static HRESULT
Compartment_Constructor(CompartmentValue
*value
, ITfCompartment
**ppOut
);
83 static inline CompartmentMgr
*impl_from_ITfCompartmentMgr(ITfCompartmentMgr
*iface
)
85 return CONTAINING_RECORD(iface
, CompartmentMgr
, ITfCompartmentMgr_iface
);
88 static inline Compartment
*impl_from_ITfCompartment(ITfCompartment
*iface
)
90 return CONTAINING_RECORD(iface
, Compartment
, ITfCompartment_iface
);
93 static inline Compartment
*impl_from_ITfSource(ITfSource
*iface
)
95 return CONTAINING_RECORD(iface
, Compartment
, ITfSource_iface
);
98 static inline CompartmentEnumGuid
*impl_from_IEnumGUID(IEnumGUID
*iface
)
100 return CONTAINING_RECORD(iface
, CompartmentEnumGuid
, IEnumGUID_iface
);
103 HRESULT
CompartmentMgr_Destructor(ITfCompartmentMgr
*iface
)
105 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
106 struct list
*cursor
, *cursor2
;
108 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->values
)
110 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
112 ITfCompartment_Release(value
->compartment
);
113 HeapFree(GetProcessHeap(),0,value
);
116 HeapFree(GetProcessHeap(),0,This
);
120 /*****************************************************
121 * ITfCompartmentMgr functions
122 *****************************************************/
123 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
125 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
127 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, ppvOut
);
132 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
134 *ppvOut
= &This
->ITfCompartmentMgr_iface
;
139 ITfCompartmentMgr_AddRef(iface
);
143 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
144 return E_NOINTERFACE
;
148 static ULONG WINAPI
CompartmentMgr_AddRef(ITfCompartmentMgr
*iface
)
150 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
152 return IUnknown_AddRef(This
->pUnkOuter
);
154 return InterlockedIncrement(&This
->refCount
);
157 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
159 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
161 return IUnknown_Release(This
->pUnkOuter
);
166 ret
= InterlockedDecrement(&This
->refCount
);
168 CompartmentMgr_Destructor(iface
);
173 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
174 REFGUID rguid
, ITfCompartment
**ppcomp
)
176 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
177 CompartmentValue
* value
;
181 TRACE("(%p) %s %p\n",This
,debugstr_guid(rguid
),ppcomp
);
183 LIST_FOR_EACH(cursor
, &This
->values
)
185 value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
186 if (IsEqualGUID(rguid
,&value
->guid
))
188 ITfCompartment_AddRef(value
->compartment
);
189 *ppcomp
= value
->compartment
;
194 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
195 value
->guid
= *rguid
;
197 hr
= Compartment_Constructor(value
,&value
->compartment
);
200 list_add_head(&This
->values
,&value
->entry
);
201 ITfCompartment_AddRef(value
->compartment
);
202 *ppcomp
= value
->compartment
;
206 HeapFree(GetProcessHeap(),0,value
);
212 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
213 TfClientId tid
, REFGUID rguid
)
215 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
218 TRACE("(%p) %i %s\n",This
,tid
,debugstr_guid(rguid
));
220 LIST_FOR_EACH(cursor
, &This
->values
)
222 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
223 if (IsEqualGUID(rguid
,&value
->guid
))
225 if (value
->owner
&& tid
!= value
->owner
)
228 ITfCompartment_Release(value
->compartment
);
229 HeapFree(GetProcessHeap(),0,value
);
234 return CONNECT_E_NOCONNECTION
;
237 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
240 CompartmentMgr
*This
= impl_from_ITfCompartmentMgr(iface
);
242 TRACE("(%p) %p\n",This
,ppEnum
);
245 return CompartmentEnumGuid_Constructor(&This
->values
, ppEnum
);
248 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl
=
250 CompartmentMgr_QueryInterface
,
251 CompartmentMgr_AddRef
,
252 CompartmentMgr_Release
,
253 CompartmentMgr_GetCompartment
,
254 CompartmentMgr_ClearCompartment
,
255 CompartmentMgr_EnumCompartments
258 HRESULT
CompartmentMgr_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, IUnknown
**ppOut
)
260 CompartmentMgr
*This
;
265 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
266 return CLASS_E_NOAGGREGATION
;
268 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
270 return E_OUTOFMEMORY
;
272 This
->ITfCompartmentMgr_iface
.lpVtbl
= &CompartmentMgrVtbl
;
273 This
->pUnkOuter
= pUnkOuter
;
274 list_init(&This
->values
);
278 *ppOut
= (IUnknown
*)&This
->ITfCompartmentMgr_iface
;
279 TRACE("returning %p\n", *ppOut
);
285 hr
= ITfCompartmentMgr_QueryInterface(&This
->ITfCompartmentMgr_iface
, riid
, (void**)ppOut
);
287 HeapFree(GetProcessHeap(),0,This
);
292 /**************************************************
293 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
294 **************************************************/
295 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid
*This
)
297 TRACE("destroying %p\n", This
);
298 HeapFree(GetProcessHeap(),0,This
);
301 static HRESULT WINAPI
CompartmentEnumGuid_QueryInterface(IEnumGUID
*iface
, REFIID iid
, LPVOID
*ppvOut
)
303 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
306 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
308 *ppvOut
= &This
->IEnumGUID_iface
;
313 IEnumGUID_AddRef(iface
);
317 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
318 return E_NOINTERFACE
;
321 static ULONG WINAPI
CompartmentEnumGuid_AddRef(IEnumGUID
*iface
)
323 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
324 return InterlockedIncrement(&This
->refCount
);
327 static ULONG WINAPI
CompartmentEnumGuid_Release(IEnumGUID
*iface
)
329 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
332 ret
= InterlockedDecrement(&This
->refCount
);
334 CompartmentEnumGuid_Destructor(This
);
338 /*****************************************************
339 * IEnumGuid functions
340 *****************************************************/
341 static HRESULT WINAPI
CompartmentEnumGuid_Next(IEnumGUID
*iface
,
342 ULONG celt
, GUID
*rgelt
, ULONG
*pceltFetched
)
344 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
347 TRACE("(%p)\n",This
);
349 if (rgelt
== NULL
) return E_POINTER
;
351 while (fetched
< celt
&& This
->cursor
)
353 CompartmentValue
* value
= LIST_ENTRY(This
->cursor
,CompartmentValue
,entry
);
357 This
->cursor
= list_next(This
->values
,This
->cursor
);
358 *rgelt
= value
->guid
;
364 if (pceltFetched
) *pceltFetched
= fetched
;
365 return fetched
== celt
? S_OK
: S_FALSE
;
368 static HRESULT WINAPI
CompartmentEnumGuid_Skip(IEnumGUID
*iface
, ULONG celt
)
370 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
371 TRACE("(%p)\n",This
);
373 This
->cursor
= list_next(This
->values
,This
->cursor
);
377 static HRESULT WINAPI
CompartmentEnumGuid_Reset(IEnumGUID
*iface
)
379 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
380 TRACE("(%p)\n",This
);
381 This
->cursor
= list_head(This
->values
);
385 static HRESULT WINAPI
CompartmentEnumGuid_Clone(IEnumGUID
*iface
,
388 CompartmentEnumGuid
*This
= impl_from_IEnumGUID(iface
);
391 TRACE("(%p)\n",This
);
393 if (ppenum
== NULL
) return E_POINTER
;
395 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
398 CompartmentEnumGuid
*new_This
= impl_from_IEnumGUID(*ppenum
);
399 new_This
->cursor
= This
->cursor
;
404 static const IEnumGUIDVtbl EnumGUIDVtbl
=
406 CompartmentEnumGuid_QueryInterface
,
407 CompartmentEnumGuid_AddRef
,
408 CompartmentEnumGuid_Release
,
409 CompartmentEnumGuid_Next
,
410 CompartmentEnumGuid_Skip
,
411 CompartmentEnumGuid_Reset
,
412 CompartmentEnumGuid_Clone
415 static HRESULT
CompartmentEnumGuid_Constructor(struct list
*values
, IEnumGUID
**ppOut
)
417 CompartmentEnumGuid
*This
;
419 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentEnumGuid
));
421 return E_OUTOFMEMORY
;
423 This
->IEnumGUID_iface
.lpVtbl
= &EnumGUIDVtbl
;
426 This
->values
= values
;
427 This
->cursor
= list_head(values
);
429 *ppOut
= &This
->IEnumGUID_iface
;
430 TRACE("returning %p\n", *ppOut
);
434 /**************************************************
436 **************************************************/
437 static void Compartment_Destructor(Compartment
*This
)
439 TRACE("destroying %p\n", This
);
440 VariantClear(&This
->variant
);
441 free_sinks(&This
->CompartmentEventSink
);
442 HeapFree(GetProcessHeap(),0,This
);
445 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
447 Compartment
*This
= impl_from_ITfCompartment(iface
);
451 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartment
))
453 *ppvOut
= &This
->ITfCompartment_iface
;
455 else if (IsEqualIID(iid
, &IID_ITfSource
))
457 *ppvOut
= &This
->ITfSource_iface
;
462 ITfCompartment_AddRef(iface
);
466 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
467 return E_NOINTERFACE
;
470 static ULONG WINAPI
Compartment_AddRef(ITfCompartment
*iface
)
472 Compartment
*This
= impl_from_ITfCompartment(iface
);
473 return InterlockedIncrement(&This
->refCount
);
476 static ULONG WINAPI
Compartment_Release(ITfCompartment
*iface
)
478 Compartment
*This
= impl_from_ITfCompartment(iface
);
481 ret
= InterlockedDecrement(&This
->refCount
);
483 Compartment_Destructor(This
);
487 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
488 TfClientId tid
, const VARIANT
*pvarValue
)
490 Compartment
*This
= impl_from_ITfCompartment(iface
);
491 ITfCompartmentEventSink
*sink
;
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 SINK_FOR_EACH(cursor
, &This
->CompartmentEventSink
, ITfCompartmentEventSink
, sink
)
519 ITfCompartmentEventSink_OnChange(sink
, &This
->valueData
->guid
);
525 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
528 Compartment
*This
= impl_from_ITfCompartment(iface
);
529 TRACE("(%p) %p\n",This
, pvarValue
);
534 VariantInit(pvarValue
);
535 if (V_VT(&This
->variant
) == VT_EMPTY
) return S_FALSE
;
536 return VariantCopy(pvarValue
,&This
->variant
);
539 static const ITfCompartmentVtbl CompartmentVtbl
=
541 Compartment_QueryInterface
,
544 Compartment_SetValue
,
548 /*****************************************************
549 * ITfSource functions
550 *****************************************************/
552 static HRESULT WINAPI
CompartmentSource_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
554 Compartment
*This
= impl_from_ITfSource(iface
);
555 return ITfCompartment_QueryInterface(&This
->ITfCompartment_iface
, iid
, ppvOut
);
558 static ULONG WINAPI
CompartmentSource_AddRef(ITfSource
*iface
)
560 Compartment
*This
= impl_from_ITfSource(iface
);
561 return ITfCompartment_AddRef(&This
->ITfCompartment_iface
);
564 static ULONG WINAPI
CompartmentSource_Release(ITfSource
*iface
)
566 Compartment
*This
= impl_from_ITfSource(iface
);
567 return ITfCompartment_Release(&This
->ITfCompartment_iface
);
570 static HRESULT WINAPI
CompartmentSource_AdviseSink(ITfSource
*iface
,
571 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
573 Compartment
*This
= impl_from_ITfSource(iface
);
575 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
577 if (!riid
|| !punk
|| !pdwCookie
)
580 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
581 return advise_sink(&This
->CompartmentEventSink
, &IID_ITfCompartmentEventSink
,
582 COOKIE_MAGIC_COMPARTMENTSINK
, punk
, pdwCookie
);
584 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
588 static HRESULT WINAPI
CompartmentSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
590 Compartment
*This
= impl_from_ITfSource(iface
);
592 TRACE("(%p) %x\n",This
,pdwCookie
);
594 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_COMPARTMENTSINK
)
597 return unadvise_sink(pdwCookie
);
600 static const ITfSourceVtbl CompartmentSourceVtbl
=
602 CompartmentSource_QueryInterface
,
603 CompartmentSource_AddRef
,
604 CompartmentSource_Release
,
605 CompartmentSource_AdviseSink
,
606 CompartmentSource_UnadviseSink
,
609 static HRESULT
Compartment_Constructor(CompartmentValue
*valueData
, ITfCompartment
**ppOut
)
613 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
615 return E_OUTOFMEMORY
;
617 This
->ITfCompartment_iface
.lpVtbl
= &CompartmentVtbl
;
618 This
->ITfSource_iface
.lpVtbl
= &CompartmentSourceVtbl
;
621 This
->valueData
= valueData
;
622 VariantInit(&This
->variant
);
624 list_init(&This
->CompartmentEventSink
);
626 *ppOut
= &This
->ITfCompartment_iface
;
627 TRACE("returning %p\n", *ppOut
);