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 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
31 #include <wine/debug.h>
35 //#include "winuser.h"
36 //#include "shlwapi.h"
37 //#include "winerror.h"
42 //#include "wine/unicode.h"
43 #include <wine/list.h>
46 #include "msctf_internal.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(msctf
);
50 typedef struct tagCompartmentValue
{
54 ITfCompartment
*compartment
;
57 typedef struct tagCompartmentMgr
{
58 const ITfCompartmentMgrVtbl
*CompartmentMgrVtbl
;
66 typedef struct tagCompartmentEnumGuid
{
67 const IEnumGUIDVtbl
*Vtbl
;
72 } CompartmentEnumGuid
;
75 typedef struct tagCompartmentSink
{
79 ITfCompartmentEventSink
*pITfCompartmentEventSink
;
83 typedef struct tagCompartment
{
84 const ITfCompartmentVtbl
*Vtbl
;
85 const ITfSourceVtbl
*SourceVtbl
;
88 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
90 CompartmentValue
*valueData
;
91 struct list CompartmentEventSink
;
94 static HRESULT
CompartmentEnumGuid_Constructor(struct list
* values
, IEnumGUID
**ppOut
);
95 static HRESULT
Compartment_Constructor(CompartmentValue
*value
, ITfCompartment
**ppOut
);
97 static inline Compartment
*impl_from_ITfSourceVtbl(ITfSource
*iface
)
99 return (Compartment
*)((char *)iface
- FIELD_OFFSET(Compartment
,SourceVtbl
));
102 HRESULT
CompartmentMgr_Destructor(ITfCompartmentMgr
*iface
)
104 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
105 struct list
*cursor
, *cursor2
;
107 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->values
)
109 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
111 ITfCompartment_Release(value
->compartment
);
112 HeapFree(GetProcessHeap(),0,value
);
115 HeapFree(GetProcessHeap(),0,This
);
119 /*****************************************************
120 * ITfCompartmentMgr functions
121 *****************************************************/
122 static HRESULT WINAPI
CompartmentMgr_QueryInterface(ITfCompartmentMgr
*iface
, REFIID iid
, LPVOID
*ppvOut
)
124 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
126 return IUnknown_QueryInterface(This
->pUnkOuter
, iid
, *ppvOut
);
131 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartmentMgr
))
138 IUnknown_AddRef(iface
);
142 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
143 return E_NOINTERFACE
;
147 static ULONG WINAPI
CompartmentMgr_AddRef(ITfCompartmentMgr
*iface
)
149 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
151 return IUnknown_AddRef(This
->pUnkOuter
);
153 return InterlockedIncrement(&This
->refCount
);
156 static ULONG WINAPI
CompartmentMgr_Release(ITfCompartmentMgr
*iface
)
158 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
160 return IUnknown_Release(This
->pUnkOuter
);
165 ret
= InterlockedDecrement(&This
->refCount
);
167 CompartmentMgr_Destructor(iface
);
172 static HRESULT WINAPI
CompartmentMgr_GetCompartment(ITfCompartmentMgr
*iface
,
173 REFGUID rguid
, ITfCompartment
**ppcomp
)
175 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
176 CompartmentValue
* value
;
180 TRACE("(%p) %s %p\n",This
,debugstr_guid(rguid
),ppcomp
);
182 LIST_FOR_EACH(cursor
, &This
->values
)
184 value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
185 if (IsEqualGUID(rguid
,&value
->guid
))
187 ITfCompartment_AddRef(value
->compartment
);
188 *ppcomp
= value
->compartment
;
193 value
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue
));
194 value
->guid
= *rguid
;
196 hr
= Compartment_Constructor(value
,&value
->compartment
);
199 list_add_head(&This
->values
,&value
->entry
);
200 ITfCompartment_AddRef(value
->compartment
);
201 *ppcomp
= value
->compartment
;
205 HeapFree(GetProcessHeap(),0,value
);
211 static HRESULT WINAPI
CompartmentMgr_ClearCompartment(ITfCompartmentMgr
*iface
,
212 TfClientId tid
, REFGUID rguid
)
215 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
216 TRACE("(%p) %i %s\n",This
,tid
,debugstr_guid(rguid
));
218 LIST_FOR_EACH(cursor
, &This
->values
)
220 CompartmentValue
* value
= LIST_ENTRY(cursor
,CompartmentValue
,entry
);
221 if (IsEqualGUID(rguid
,&value
->guid
))
223 if (value
->owner
&& tid
!= value
->owner
)
226 ITfCompartment_Release(value
->compartment
);
227 HeapFree(GetProcessHeap(),0,value
);
232 return CONNECT_E_NOCONNECTION
;
235 static HRESULT WINAPI
CompartmentMgr_EnumCompartments(ITfCompartmentMgr
*iface
,
238 CompartmentMgr
*This
= (CompartmentMgr
*)iface
;
239 TRACE("(%p) %p\n",This
,ppEnum
);
242 return CompartmentEnumGuid_Constructor(&This
->values
, ppEnum
);
245 static const ITfCompartmentMgrVtbl CompartmentMgr_CompartmentMgrVtbl
=
247 CompartmentMgr_QueryInterface
,
248 CompartmentMgr_AddRef
,
249 CompartmentMgr_Release
,
251 CompartmentMgr_GetCompartment
,
252 CompartmentMgr_ClearCompartment
,
253 CompartmentMgr_EnumCompartments
256 HRESULT
CompartmentMgr_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, IUnknown
**ppOut
)
258 CompartmentMgr
*This
;
263 if (pUnkOuter
&& !IsEqualIID (riid
, &IID_IUnknown
))
264 return CLASS_E_NOAGGREGATION
;
266 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentMgr
));
268 return E_OUTOFMEMORY
;
270 This
->CompartmentMgrVtbl
= &CompartmentMgr_CompartmentMgrVtbl
;
271 This
->pUnkOuter
= pUnkOuter
;
272 list_init(&This
->values
);
276 TRACE("returning %p\n", This
);
277 *ppOut
= (IUnknown
*)This
;
283 hr
= IUnknown_QueryInterface((IUnknown
*)This
, riid
, (LPVOID
*)ppOut
);
285 HeapFree(GetProcessHeap(),0,This
);
290 /**************************************************
291 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
292 **************************************************/
293 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid
*This
)
295 TRACE("destroying %p\n", This
);
296 HeapFree(GetProcessHeap(),0,This
);
299 static HRESULT WINAPI
CompartmentEnumGuid_QueryInterface(IEnumGUID
*iface
, REFIID iid
, LPVOID
*ppvOut
)
301 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
304 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IEnumGUID
))
311 IUnknown_AddRef(iface
);
315 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
316 return E_NOINTERFACE
;
319 static ULONG WINAPI
CompartmentEnumGuid_AddRef(IEnumGUID
*iface
)
321 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
322 return InterlockedIncrement(&This
->refCount
);
325 static ULONG WINAPI
CompartmentEnumGuid_Release(IEnumGUID
*iface
)
327 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
330 ret
= InterlockedDecrement(&This
->refCount
);
332 CompartmentEnumGuid_Destructor(This
);
336 /*****************************************************
337 * IEnumGuid functions
338 *****************************************************/
339 static HRESULT WINAPI
CompartmentEnumGuid_Next( LPENUMGUID iface
,
340 ULONG celt
, GUID
*rgelt
, ULONG
*pceltFetched
)
342 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
345 TRACE("(%p)\n",This
);
347 if (rgelt
== NULL
) return E_POINTER
;
349 while (fetched
< celt
&& This
->cursor
)
351 CompartmentValue
* value
= LIST_ENTRY(This
->cursor
,CompartmentValue
,entry
);
355 This
->cursor
= list_next(This
->values
,This
->cursor
);
356 *rgelt
= value
->guid
;
362 if (pceltFetched
) *pceltFetched
= fetched
;
363 return fetched
== celt
? S_OK
: S_FALSE
;
366 static HRESULT WINAPI
CompartmentEnumGuid_Skip( LPENUMGUID iface
, ULONG celt
)
368 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
369 TRACE("(%p)\n",This
);
371 This
->cursor
= list_next(This
->values
,This
->cursor
);
375 static HRESULT WINAPI
CompartmentEnumGuid_Reset( LPENUMGUID iface
)
377 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
378 TRACE("(%p)\n",This
);
379 This
->cursor
= list_head(This
->values
);
383 static HRESULT WINAPI
CompartmentEnumGuid_Clone( LPENUMGUID iface
,
386 CompartmentEnumGuid
*This
= (CompartmentEnumGuid
*)iface
;
389 TRACE("(%p)\n",This
);
391 if (ppenum
== NULL
) return E_POINTER
;
393 res
= CompartmentEnumGuid_Constructor(This
->values
, ppenum
);
396 CompartmentEnumGuid
*new_This
= (CompartmentEnumGuid
*)*ppenum
;
397 new_This
->cursor
= This
->cursor
;
402 static const IEnumGUIDVtbl IEnumGUID_Vtbl
={
403 CompartmentEnumGuid_QueryInterface
,
404 CompartmentEnumGuid_AddRef
,
405 CompartmentEnumGuid_Release
,
407 CompartmentEnumGuid_Next
,
408 CompartmentEnumGuid_Skip
,
409 CompartmentEnumGuid_Reset
,
410 CompartmentEnumGuid_Clone
413 static HRESULT
CompartmentEnumGuid_Constructor(struct list
*values
, IEnumGUID
**ppOut
)
415 CompartmentEnumGuid
*This
;
417 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(CompartmentEnumGuid
));
419 return E_OUTOFMEMORY
;
421 This
->Vtbl
= &IEnumGUID_Vtbl
;
424 This
->values
= values
;
425 This
->cursor
= list_head(values
);
427 TRACE("returning %p\n", This
);
428 *ppOut
= (IEnumGUID
*)This
;
432 /**************************************************
434 **************************************************/
435 static void free_sink(CompartmentSink
*sink
)
437 IUnknown_Release(sink
->interfaces
.pIUnknown
);
438 HeapFree(GetProcessHeap(),0,sink
);
441 static void Compartment_Destructor(Compartment
*This
)
443 struct list
*cursor
, *cursor2
;
444 TRACE("destroying %p\n", This
);
445 VariantClear(&This
->variant
);
446 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &This
->CompartmentEventSink
)
448 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
452 HeapFree(GetProcessHeap(),0,This
);
455 static HRESULT WINAPI
Compartment_QueryInterface(ITfCompartment
*iface
, REFIID iid
, LPVOID
*ppvOut
)
457 Compartment
*This
= (Compartment
*)iface
;
460 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ITfCompartment
))
464 else if (IsEqualIID(iid
, &IID_ITfSource
))
466 *ppvOut
= &This
->SourceVtbl
;
471 IUnknown_AddRef(iface
);
475 WARN("unsupported interface: %s\n", debugstr_guid(iid
));
476 return E_NOINTERFACE
;
479 static ULONG WINAPI
Compartment_AddRef(ITfCompartment
*iface
)
481 Compartment
*This
= (Compartment
*)iface
;
482 return InterlockedIncrement(&This
->refCount
);
485 static ULONG WINAPI
Compartment_Release(ITfCompartment
*iface
)
487 Compartment
*This
= (Compartment
*)iface
;
490 ret
= InterlockedDecrement(&This
->refCount
);
492 Compartment_Destructor(This
);
496 static HRESULT WINAPI
Compartment_SetValue(ITfCompartment
*iface
,
497 TfClientId tid
, const VARIANT
*pvarValue
)
499 Compartment
*This
= (Compartment
*)iface
;
502 TRACE("(%p) %i %p\n",This
,tid
,pvarValue
);
507 if (!(V_VT(pvarValue
) == VT_BSTR
|| V_VT(pvarValue
) == VT_I4
||
508 V_VT(pvarValue
) == VT_UNKNOWN
))
511 if (!This
->valueData
->owner
)
512 This
->valueData
->owner
= tid
;
514 VariantClear(&This
->variant
);
516 /* Shallow copy of value and type */
517 This
->variant
= *pvarValue
;
519 if (V_VT(pvarValue
) == VT_BSTR
)
520 V_BSTR(&This
->variant
) = SysAllocStringByteLen((char*)V_BSTR(pvarValue
),
521 SysStringByteLen(V_BSTR(pvarValue
)));
522 else if (V_VT(pvarValue
) == VT_UNKNOWN
)
523 IUnknown_AddRef(V_UNKNOWN(&This
->variant
));
525 LIST_FOR_EACH(cursor
, &This
->CompartmentEventSink
)
527 CompartmentSink
* sink
= LIST_ENTRY(cursor
,CompartmentSink
,entry
);
528 ITfCompartmentEventSink_OnChange(sink
->interfaces
.pITfCompartmentEventSink
,&This
->valueData
->guid
);
534 static HRESULT WINAPI
Compartment_GetValue(ITfCompartment
*iface
,
537 Compartment
*This
= (Compartment
*)iface
;
538 TRACE("(%p) %p\n",This
, pvarValue
);
543 VariantInit(pvarValue
);
544 if (V_VT(&This
->variant
) == VT_EMPTY
) return S_FALSE
;
545 return VariantCopy(pvarValue
,&This
->variant
);
548 static const ITfCompartmentVtbl ITfCompartment_Vtbl
={
549 Compartment_QueryInterface
,
553 Compartment_SetValue
,
557 /*****************************************************
558 * ITfSource functions
559 *****************************************************/
561 static HRESULT WINAPI
Source_QueryInterface(ITfSource
*iface
, REFIID iid
, LPVOID
*ppvOut
)
563 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
564 return Compartment_QueryInterface((ITfCompartment
*)This
, iid
, *ppvOut
);
567 static ULONG WINAPI
Source_AddRef(ITfSource
*iface
)
569 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
570 return Compartment_AddRef((ITfCompartment
*)This
);
573 static ULONG WINAPI
Source_Release(ITfSource
*iface
)
575 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
576 return Compartment_Release((ITfCompartment
*)This
);
579 static HRESULT WINAPI
CompartmentSource_AdviseSink(ITfSource
*iface
,
580 REFIID riid
, IUnknown
*punk
, DWORD
*pdwCookie
)
583 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
585 TRACE("(%p) %s %p %p\n",This
,debugstr_guid(riid
),punk
,pdwCookie
);
587 if (!riid
|| !punk
|| !pdwCookie
)
590 if (IsEqualIID(riid
, &IID_ITfCompartmentEventSink
))
592 cs
= HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink
));
594 return E_OUTOFMEMORY
;
595 if (FAILED(IUnknown_QueryInterface(punk
, riid
, (LPVOID
*)&cs
->interfaces
.pITfCompartmentEventSink
)))
597 HeapFree(GetProcessHeap(),0,cs
);
598 return CONNECT_E_CANNOTCONNECT
;
600 list_add_head(&This
->CompartmentEventSink
,&cs
->entry
);
601 *pdwCookie
= generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK
, cs
);
605 FIXME("(%p) Unhandled Sink: %s\n",This
,debugstr_guid(riid
));
609 TRACE("cookie %x\n",*pdwCookie
);
614 static HRESULT WINAPI
CompartmentSource_UnadviseSink(ITfSource
*iface
, DWORD pdwCookie
)
616 CompartmentSink
*sink
;
617 Compartment
*This
= impl_from_ITfSourceVtbl(iface
);
619 TRACE("(%p) %x\n",This
,pdwCookie
);
621 if (get_Cookie_magic(pdwCookie
)!=COOKIE_MAGIC_COMPARTMENTSINK
)
624 sink
= (CompartmentSink
*)remove_Cookie(pdwCookie
);
626 return CONNECT_E_NOCONNECTION
;
628 list_remove(&sink
->entry
);
634 static const ITfSourceVtbl Compartment_SourceVtbl
=
636 Source_QueryInterface
,
640 CompartmentSource_AdviseSink
,
641 CompartmentSource_UnadviseSink
,
644 static HRESULT
Compartment_Constructor(CompartmentValue
*valueData
, ITfCompartment
**ppOut
)
648 This
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(Compartment
));
650 return E_OUTOFMEMORY
;
652 This
->Vtbl
= &ITfCompartment_Vtbl
;
653 This
->SourceVtbl
= &Compartment_SourceVtbl
;
656 This
->valueData
= valueData
;
657 VariantInit(&This
->variant
);
659 list_init(&This
->CompartmentEventSink
);
661 TRACE("returning %p\n", This
);
662 *ppOut
= (ITfCompartment
*)This
;