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