[MSCMS] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / msctf / compartmentmgr.c
1 /*
2 * ITfCompartmentMgr implementation
3 *
4 * Copyright 2009 Aric Stewart, CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "msctf_internal.h"
22
23 #include <oleauto.h>
24
25 typedef struct tagCompartmentValue {
26 struct list entry;
27 GUID guid;
28 TfClientId owner;
29 ITfCompartment *compartment;
30 } CompartmentValue;
31
32 typedef struct tagCompartmentMgr {
33 ITfCompartmentMgr ITfCompartmentMgr_iface;
34 LONG refCount;
35
36 IUnknown *pUnkOuter;
37
38 struct list values;
39 } CompartmentMgr;
40
41 typedef struct tagCompartmentEnumGuid {
42 IEnumGUID IEnumGUID_iface;
43 LONG refCount;
44
45 struct list *values;
46 struct list *cursor;
47 } CompartmentEnumGuid;
48
49 typedef struct tagCompartment {
50 ITfCompartment ITfCompartment_iface;
51 ITfSource ITfSource_iface;
52 LONG refCount;
53
54 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
55 VARIANT variant;
56 CompartmentValue *valueData;
57 struct list CompartmentEventSink;
58 } Compartment;
59
60 static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut);
61 static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut);
62
63 static inline CompartmentMgr *impl_from_ITfCompartmentMgr(ITfCompartmentMgr *iface)
64 {
65 return CONTAINING_RECORD(iface, CompartmentMgr, ITfCompartmentMgr_iface);
66 }
67
68 static inline Compartment *impl_from_ITfCompartment(ITfCompartment *iface)
69 {
70 return CONTAINING_RECORD(iface, Compartment, ITfCompartment_iface);
71 }
72
73 static inline Compartment *impl_from_ITfSource(ITfSource *iface)
74 {
75 return CONTAINING_RECORD(iface, Compartment, ITfSource_iface);
76 }
77
78 static inline CompartmentEnumGuid *impl_from_IEnumGUID(IEnumGUID *iface)
79 {
80 return CONTAINING_RECORD(iface, CompartmentEnumGuid, IEnumGUID_iface);
81 }
82
83 HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface)
84 {
85 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
86 struct list *cursor, *cursor2;
87
88 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values)
89 {
90 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
91 list_remove(cursor);
92 ITfCompartment_Release(value->compartment);
93 HeapFree(GetProcessHeap(),0,value);
94 }
95
96 HeapFree(GetProcessHeap(),0,This);
97 return S_OK;
98 }
99
100 /*****************************************************
101 * ITfCompartmentMgr functions
102 *****************************************************/
103 static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut)
104 {
105 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
106 if (This->pUnkOuter)
107 return IUnknown_QueryInterface(This->pUnkOuter, iid, ppvOut);
108 else
109 {
110 *ppvOut = NULL;
111
112 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr))
113 {
114 *ppvOut = &This->ITfCompartmentMgr_iface;
115 }
116
117 if (*ppvOut)
118 {
119 ITfCompartmentMgr_AddRef(iface);
120 return S_OK;
121 }
122
123 WARN("unsupported interface: %s\n", debugstr_guid(iid));
124 return E_NOINTERFACE;
125 }
126 }
127
128 static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface)
129 {
130 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
131 if (This->pUnkOuter)
132 return IUnknown_AddRef(This->pUnkOuter);
133 else
134 return InterlockedIncrement(&This->refCount);
135 }
136
137 static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface)
138 {
139 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
140 if (This->pUnkOuter)
141 return IUnknown_Release(This->pUnkOuter);
142 else
143 {
144 ULONG ret;
145
146 ret = InterlockedDecrement(&This->refCount);
147 if (ret == 0)
148 CompartmentMgr_Destructor(iface);
149 return ret;
150 }
151 }
152
153 static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface,
154 REFGUID rguid, ITfCompartment **ppcomp)
155 {
156 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
157 CompartmentValue* value;
158 struct list *cursor;
159 HRESULT hr;
160
161 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),ppcomp);
162
163 LIST_FOR_EACH(cursor, &This->values)
164 {
165 value = LIST_ENTRY(cursor,CompartmentValue,entry);
166 if (IsEqualGUID(rguid,&value->guid))
167 {
168 ITfCompartment_AddRef(value->compartment);
169 *ppcomp = value->compartment;
170 return S_OK;
171 }
172 }
173
174 value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue));
175 value->guid = *rguid;
176 value->owner = 0;
177 hr = Compartment_Constructor(value,&value->compartment);
178 if (SUCCEEDED(hr))
179 {
180 list_add_head(&This->values,&value->entry);
181 ITfCompartment_AddRef(value->compartment);
182 *ppcomp = value->compartment;
183 }
184 else
185 {
186 HeapFree(GetProcessHeap(),0,value);
187 *ppcomp = NULL;
188 }
189 return hr;
190 }
191
192 static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface,
193 TfClientId tid, REFGUID rguid)
194 {
195 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
196 struct list *cursor;
197
198 TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid));
199
200 LIST_FOR_EACH(cursor, &This->values)
201 {
202 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
203 if (IsEqualGUID(rguid,&value->guid))
204 {
205 if (value->owner && tid != value->owner)
206 return E_UNEXPECTED;
207 list_remove(cursor);
208 ITfCompartment_Release(value->compartment);
209 HeapFree(GetProcessHeap(),0,value);
210 return S_OK;
211 }
212 }
213
214 return CONNECT_E_NOCONNECTION;
215 }
216
217 static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface,
218 IEnumGUID **ppEnum)
219 {
220 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
221
222 TRACE("(%p) %p\n",This,ppEnum);
223 if (!ppEnum)
224 return E_INVALIDARG;
225 return CompartmentEnumGuid_Constructor(&This->values, ppEnum);
226 }
227
228 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl =
229 {
230 CompartmentMgr_QueryInterface,
231 CompartmentMgr_AddRef,
232 CompartmentMgr_Release,
233 CompartmentMgr_GetCompartment,
234 CompartmentMgr_ClearCompartment,
235 CompartmentMgr_EnumCompartments
236 };
237
238 HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut)
239 {
240 CompartmentMgr *This;
241
242 if (!ppOut)
243 return E_POINTER;
244
245 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
246 return CLASS_E_NOAGGREGATION;
247
248 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr));
249 if (This == NULL)
250 return E_OUTOFMEMORY;
251
252 This->ITfCompartmentMgr_iface.lpVtbl = &CompartmentMgrVtbl;
253 This->pUnkOuter = pUnkOuter;
254 list_init(&This->values);
255
256 if (pUnkOuter)
257 {
258 *ppOut = (IUnknown*)&This->ITfCompartmentMgr_iface;
259 TRACE("returning %p\n", *ppOut);
260 return S_OK;
261 }
262 else
263 {
264 HRESULT hr;
265 hr = ITfCompartmentMgr_QueryInterface(&This->ITfCompartmentMgr_iface, riid, (void**)ppOut);
266 if (FAILED(hr))
267 HeapFree(GetProcessHeap(),0,This);
268 return hr;
269 }
270 }
271
272 /**************************************************
273 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
274 **************************************************/
275 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This)
276 {
277 TRACE("destroying %p\n", This);
278 HeapFree(GetProcessHeap(),0,This);
279 }
280
281 static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
282 {
283 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
284 *ppvOut = NULL;
285
286 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
287 {
288 *ppvOut = &This->IEnumGUID_iface;
289 }
290
291 if (*ppvOut)
292 {
293 IEnumGUID_AddRef(iface);
294 return S_OK;
295 }
296
297 WARN("unsupported interface: %s\n", debugstr_guid(iid));
298 return E_NOINTERFACE;
299 }
300
301 static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface)
302 {
303 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
304 return InterlockedIncrement(&This->refCount);
305 }
306
307 static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface)
308 {
309 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
310 ULONG ret;
311
312 ret = InterlockedDecrement(&This->refCount);
313 if (ret == 0)
314 CompartmentEnumGuid_Destructor(This);
315 return ret;
316 }
317
318 /*****************************************************
319 * IEnumGuid functions
320 *****************************************************/
321 static HRESULT WINAPI CompartmentEnumGuid_Next(IEnumGUID *iface,
322 ULONG celt, GUID *rgelt, ULONG *pceltFetched)
323 {
324 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
325 ULONG fetched = 0;
326
327 TRACE("(%p)\n",This);
328
329 if (rgelt == NULL) return E_POINTER;
330
331 while (fetched < celt && This->cursor)
332 {
333 CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry);
334 if (!value)
335 break;
336
337 This->cursor = list_next(This->values,This->cursor);
338 *rgelt = value->guid;
339
340 ++fetched;
341 ++rgelt;
342 }
343
344 if (pceltFetched) *pceltFetched = fetched;
345 return fetched == celt ? S_OK : S_FALSE;
346 }
347
348 static HRESULT WINAPI CompartmentEnumGuid_Skip(IEnumGUID *iface, ULONG celt)
349 {
350 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
351 TRACE("(%p)\n",This);
352
353 This->cursor = list_next(This->values,This->cursor);
354 return S_OK;
355 }
356
357 static HRESULT WINAPI CompartmentEnumGuid_Reset(IEnumGUID *iface)
358 {
359 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
360 TRACE("(%p)\n",This);
361 This->cursor = list_head(This->values);
362 return S_OK;
363 }
364
365 static HRESULT WINAPI CompartmentEnumGuid_Clone(IEnumGUID *iface,
366 IEnumGUID **ppenum)
367 {
368 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
369 HRESULT res;
370
371 TRACE("(%p)\n",This);
372
373 if (ppenum == NULL) return E_POINTER;
374
375 res = CompartmentEnumGuid_Constructor(This->values, ppenum);
376 if (SUCCEEDED(res))
377 {
378 CompartmentEnumGuid *new_This = impl_from_IEnumGUID(*ppenum);
379 new_This->cursor = This->cursor;
380 }
381 return res;
382 }
383
384 static const IEnumGUIDVtbl EnumGUIDVtbl =
385 {
386 CompartmentEnumGuid_QueryInterface,
387 CompartmentEnumGuid_AddRef,
388 CompartmentEnumGuid_Release,
389 CompartmentEnumGuid_Next,
390 CompartmentEnumGuid_Skip,
391 CompartmentEnumGuid_Reset,
392 CompartmentEnumGuid_Clone
393 };
394
395 static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut)
396 {
397 CompartmentEnumGuid *This;
398
399 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid));
400 if (This == NULL)
401 return E_OUTOFMEMORY;
402
403 This->IEnumGUID_iface.lpVtbl= &EnumGUIDVtbl;
404 This->refCount = 1;
405
406 This->values = values;
407 This->cursor = list_head(values);
408
409 *ppOut = &This->IEnumGUID_iface;
410 TRACE("returning %p\n", *ppOut);
411 return S_OK;
412 }
413
414 /**************************************************
415 * ITfCompartment
416 **************************************************/
417 static void Compartment_Destructor(Compartment *This)
418 {
419 TRACE("destroying %p\n", This);
420 VariantClear(&This->variant);
421 free_sinks(&This->CompartmentEventSink);
422 HeapFree(GetProcessHeap(),0,This);
423 }
424
425 static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut)
426 {
427 Compartment *This = impl_from_ITfCompartment(iface);
428
429 *ppvOut = NULL;
430
431 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment))
432 {
433 *ppvOut = &This->ITfCompartment_iface;
434 }
435 else if (IsEqualIID(iid, &IID_ITfSource))
436 {
437 *ppvOut = &This->ITfSource_iface;
438 }
439
440 if (*ppvOut)
441 {
442 ITfCompartment_AddRef(iface);
443 return S_OK;
444 }
445
446 WARN("unsupported interface: %s\n", debugstr_guid(iid));
447 return E_NOINTERFACE;
448 }
449
450 static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface)
451 {
452 Compartment *This = impl_from_ITfCompartment(iface);
453 return InterlockedIncrement(&This->refCount);
454 }
455
456 static ULONG WINAPI Compartment_Release(ITfCompartment *iface)
457 {
458 Compartment *This = impl_from_ITfCompartment(iface);
459 ULONG ret;
460
461 ret = InterlockedDecrement(&This->refCount);
462 if (ret == 0)
463 Compartment_Destructor(This);
464 return ret;
465 }
466
467 static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface,
468 TfClientId tid, const VARIANT *pvarValue)
469 {
470 Compartment *This = impl_from_ITfCompartment(iface);
471 ITfCompartmentEventSink *sink;
472 struct list *cursor;
473
474 TRACE("(%p) %i %p\n",This,tid,pvarValue);
475
476 if (!pvarValue)
477 return E_INVALIDARG;
478
479 if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 ||
480 V_VT(pvarValue) == VT_UNKNOWN))
481 return E_INVALIDARG;
482
483 if (!This->valueData->owner)
484 This->valueData->owner = tid;
485
486 VariantClear(&This->variant);
487
488 /* Shallow copy of value and type */
489 This->variant = *pvarValue;
490
491 if (V_VT(pvarValue) == VT_BSTR)
492 V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue),
493 SysStringByteLen(V_BSTR(pvarValue)));
494 else if (V_VT(pvarValue) == VT_UNKNOWN)
495 IUnknown_AddRef(V_UNKNOWN(&This->variant));
496
497 SINK_FOR_EACH(cursor, &This->CompartmentEventSink, ITfCompartmentEventSink, sink)
498 {
499 ITfCompartmentEventSink_OnChange(sink, &This->valueData->guid);
500 }
501
502 return S_OK;
503 }
504
505 static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface,
506 VARIANT *pvarValue)
507 {
508 Compartment *This = impl_from_ITfCompartment(iface);
509 TRACE("(%p) %p\n",This, pvarValue);
510
511 if (!pvarValue)
512 return E_INVALIDARG;
513
514 VariantInit(pvarValue);
515 if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE;
516 return VariantCopy(pvarValue,&This->variant);
517 }
518
519 static const ITfCompartmentVtbl CompartmentVtbl =
520 {
521 Compartment_QueryInterface,
522 Compartment_AddRef,
523 Compartment_Release,
524 Compartment_SetValue,
525 Compartment_GetValue
526 };
527
528 /*****************************************************
529 * ITfSource functions
530 *****************************************************/
531
532 static HRESULT WINAPI CompartmentSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
533 {
534 Compartment *This = impl_from_ITfSource(iface);
535 return ITfCompartment_QueryInterface(&This->ITfCompartment_iface, iid, ppvOut);
536 }
537
538 static ULONG WINAPI CompartmentSource_AddRef(ITfSource *iface)
539 {
540 Compartment *This = impl_from_ITfSource(iface);
541 return ITfCompartment_AddRef(&This->ITfCompartment_iface);
542 }
543
544 static ULONG WINAPI CompartmentSource_Release(ITfSource *iface)
545 {
546 Compartment *This = impl_from_ITfSource(iface);
547 return ITfCompartment_Release(&This->ITfCompartment_iface);
548 }
549
550 static HRESULT WINAPI CompartmentSource_AdviseSink(ITfSource *iface,
551 REFIID riid, IUnknown *punk, DWORD *pdwCookie)
552 {
553 Compartment *This = impl_from_ITfSource(iface);
554
555 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
556
557 if (!riid || !punk || !pdwCookie)
558 return E_INVALIDARG;
559
560 if (IsEqualIID(riid, &IID_ITfCompartmentEventSink))
561 return advise_sink(&This->CompartmentEventSink, &IID_ITfCompartmentEventSink,
562 COOKIE_MAGIC_COMPARTMENTSINK, punk, pdwCookie);
563
564 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
565 return E_NOTIMPL;
566 }
567
568 static HRESULT WINAPI CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
569 {
570 Compartment *This = impl_from_ITfSource(iface);
571
572 TRACE("(%p) %x\n",This,pdwCookie);
573
574 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK)
575 return E_INVALIDARG;
576
577 return unadvise_sink(pdwCookie);
578 }
579
580 static const ITfSourceVtbl CompartmentSourceVtbl =
581 {
582 CompartmentSource_QueryInterface,
583 CompartmentSource_AddRef,
584 CompartmentSource_Release,
585 CompartmentSource_AdviseSink,
586 CompartmentSource_UnadviseSink,
587 };
588
589 static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut)
590 {
591 Compartment *This;
592
593 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment));
594 if (This == NULL)
595 return E_OUTOFMEMORY;
596
597 This->ITfCompartment_iface.lpVtbl= &CompartmentVtbl;
598 This->ITfSource_iface.lpVtbl = &CompartmentSourceVtbl;
599 This->refCount = 1;
600
601 This->valueData = valueData;
602 VariantInit(&This->variant);
603
604 list_init(&This->CompartmentEventSink);
605
606 *ppOut = &This->ITfCompartment_iface;
607 TRACE("returning %p\n", *ppOut);
608 return S_OK;
609 }