xref: /reactos/dll/win32/mshtml/conpoint.c (revision 50cf16b3)
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "mshtml_private.h"
20 
21 typedef struct {
22     IEnumConnections IEnumConnections_iface;
23 
24     LONG ref;
25 
26     unsigned iter;
27     ConnectionPoint *cp;
28 } EnumConnections;
29 
30 static inline EnumConnections *impl_from_IEnumConnections(IEnumConnections *iface)
31 {
32     return CONTAINING_RECORD(iface, EnumConnections, IEnumConnections_iface);
33 }
34 
35 static HRESULT WINAPI EnumConnections_QueryInterface(IEnumConnections *iface, REFIID riid, void **ppv)
36 {
37     EnumConnections *This = impl_from_IEnumConnections(iface);
38 
39     TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
40 
41     if(IsEqualGUID(riid, &IID_IUnknown)) {
42         *ppv = &This->IEnumConnections_iface;
43     }else if(IsEqualGUID(riid, &IID_IEnumConnections)) {
44         *ppv = &This->IEnumConnections_iface;
45     }else {
46         WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
47         *ppv = NULL;
48         return E_NOINTERFACE;
49     }
50 
51     IUnknown_AddRef((IUnknown*)*ppv);
52     return S_OK;
53 }
54 
55 static ULONG WINAPI EnumConnections_AddRef(IEnumConnections *iface)
56 {
57     EnumConnections *This = impl_from_IEnumConnections(iface);
58     ULONG ref = InterlockedIncrement(&This->ref);
59 
60     TRACE("(%p) ref=%d\n", This, ref);
61 
62     return ref;
63 }
64 
65 static ULONG WINAPI EnumConnections_Release(IEnumConnections *iface)
66 {
67     EnumConnections *This = impl_from_IEnumConnections(iface);
68     ULONG ref = InterlockedDecrement(&This->ref);
69 
70     TRACE("(%p) ref=%d\n", This, ref);
71 
72     if(!ref) {
73         IConnectionPoint_Release(&This->cp->IConnectionPoint_iface);
74         heap_free(This);
75     }
76 
77     return ref;
78 }
79 
80 static HRESULT WINAPI EnumConnections_Next(IEnumConnections *iface, ULONG cConnections, CONNECTDATA *rgcd, ULONG *pcFetched)
81 {
82     EnumConnections *This = impl_from_IEnumConnections(iface);
83     ULONG fetched = 0;
84 
85     TRACE("(%p)->(%d %p %p)\n", This, cConnections, rgcd, pcFetched);
86 
87     while(fetched < cConnections && This->iter < This->cp->sinks_size) {
88         if(!This->cp->sinks[This->iter].unk) {
89             This->iter++;
90             continue;
91         }
92 
93         rgcd[fetched].pUnk = This->cp->sinks[This->iter].unk;
94         rgcd[fetched].dwCookie = ++This->iter;
95         IUnknown_AddRef(rgcd[fetched].pUnk);
96         fetched++;
97     }
98 
99     if(pcFetched)
100         *pcFetched = fetched;
101     return fetched == cConnections ? S_OK : S_FALSE;
102 }
103 
104 static HRESULT WINAPI EnumConnections_Skip(IEnumConnections *iface, ULONG cConnections)
105 {
106     EnumConnections *This = impl_from_IEnumConnections(iface);
107     FIXME("(%p)->(%d)\n", This, cConnections);
108     return E_NOTIMPL;
109 }
110 
111 static HRESULT WINAPI EnumConnections_Reset(IEnumConnections *iface)
112 {
113     EnumConnections *This = impl_from_IEnumConnections(iface);
114     FIXME("(%p)\n", This);
115     return E_NOTIMPL;
116 }
117 
118 static HRESULT WINAPI EnumConnections_Clone(IEnumConnections *iface, IEnumConnections **ppEnum)
119 {
120     EnumConnections *This = impl_from_IEnumConnections(iface);
121     FIXME("(%p)->(%p)\n", This, ppEnum);
122     return E_NOTIMPL;
123 }
124 
125 static const IEnumConnectionsVtbl EnumConnectionsVtbl = {
126     EnumConnections_QueryInterface,
127     EnumConnections_AddRef,
128     EnumConnections_Release,
129     EnumConnections_Next,
130     EnumConnections_Skip,
131     EnumConnections_Reset,
132     EnumConnections_Clone
133 };
134 
135 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
136 {
137     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
138 }
139 
140 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
141                                                      REFIID riid, LPVOID *ppv)
142 {
143     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
144 
145     TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
146 
147     if(IsEqualGUID(&IID_IUnknown, riid)) {
148         *ppv = &This->IConnectionPoint_iface;
149     }else if(IsEqualGUID(&IID_IConnectionPoint, riid)) {
150         *ppv = &This->IConnectionPoint_iface;
151     }else {
152         *ppv = NULL;
153         WARN("Unsupported interface %s\n", debugstr_mshtml_guid(riid));
154         return E_NOINTERFACE;
155     }
156 
157     IUnknown_AddRef((IUnknown*)*ppv);
158     return S_OK;
159 }
160 
161 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
162 {
163     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
164     return IConnectionPointContainer_AddRef(&This->container->IConnectionPointContainer_iface);
165 }
166 
167 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
168 {
169     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
170     return IConnectionPointContainer_Release(&This->container->IConnectionPointContainer_iface);
171 }
172 
173 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID)
174 {
175     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
176 
177     TRACE("(%p)->(%p)\n", This, pIID);
178 
179     if(!pIID)
180         return E_POINTER;
181 
182     *pIID = *This->iid;
183     return S_OK;
184 }
185 
186 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
187         IConnectionPointContainer **ppCPC)
188 {
189     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
190 
191     TRACE("(%p)->(%p)\n", This, ppCPC);
192 
193     if(!ppCPC)
194         return E_POINTER;
195 
196     *ppCPC = &This->container->IConnectionPointContainer_iface;
197     IConnectionPointContainer_AddRef(*ppCPC);
198     return S_OK;
199 }
200 
201 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
202                                              DWORD *pdwCookie)
203 {
204     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
205     IUnknown *sink;
206     DWORD i;
207     HRESULT hres;
208 
209     TRACE("(%p)->(%p %p)\n", This, pUnkSink, pdwCookie);
210 
211     hres = IUnknown_QueryInterface(pUnkSink, This->iid, (void**)&sink);
212     if(FAILED(hres) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
213         hres = IUnknown_QueryInterface(pUnkSink, &IID_IDispatch, (void**)&sink);
214     if(FAILED(hres))
215         return CONNECT_E_CANNOTCONNECT;
216 
217     if(This->sinks) {
218         for(i=0; i<This->sinks_size; i++) {
219             if(!This->sinks[i].unk)
220                 break;
221         }
222 
223         if(i == This->sinks_size)
224             This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
225     }else {
226         This->sinks = heap_alloc(sizeof(*This->sinks));
227         This->sinks_size = 1;
228         i = 0;
229     }
230 
231     This->sinks[i].unk = sink;
232     if(pdwCookie)
233         *pdwCookie = i+1;
234 
235     if(!i && This->data && This->data->on_advise)
236         This->data->on_advise(This->container->outer, This->data);
237 
238     return S_OK;
239 }
240 
241 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie)
242 {
243     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
244     TRACE("(%p)->(%d)\n", This, dwCookie);
245 
246     if(!dwCookie || dwCookie > This->sinks_size || !This->sinks[dwCookie-1].unk)
247         return CONNECT_E_NOCONNECTION;
248 
249     IUnknown_Release(This->sinks[dwCookie-1].unk);
250     This->sinks[dwCookie-1].unk = NULL;
251 
252     return S_OK;
253 }
254 
255 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
256                                                       IEnumConnections **ppEnum)
257 {
258     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
259     EnumConnections *ret;
260 
261     TRACE("(%p)->(%p)\n", This, ppEnum);
262 
263     ret = heap_alloc(sizeof(*ret));
264     if(!ret)
265         return E_OUTOFMEMORY;
266 
267     ret->IEnumConnections_iface.lpVtbl = &EnumConnectionsVtbl;
268     ret->ref = 1;
269     ret->iter = 0;
270 
271     IConnectionPoint_AddRef(&This->IConnectionPoint_iface);
272     ret->cp = This;
273 
274     *ppEnum = &ret->IEnumConnections_iface;
275     return S_OK;
276 }
277 
278 static const IConnectionPointVtbl ConnectionPointVtbl =
279 {
280     ConnectionPoint_QueryInterface,
281     ConnectionPoint_AddRef,
282     ConnectionPoint_Release,
283     ConnectionPoint_GetConnectionInterface,
284     ConnectionPoint_GetConnectionPointContainer,
285     ConnectionPoint_Advise,
286     ConnectionPoint_Unadvise,
287     ConnectionPoint_EnumConnections
288 };
289 
290 static void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid, cp_static_data_t *data)
291 {
292     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
293     cp->container = container;
294     cp->sinks = NULL;
295     cp->sinks_size = 0;
296     cp->iid = riid;
297     cp->data = data;
298 }
299 
300 static void ConnectionPoint_Destroy(ConnectionPoint *This)
301 {
302     DWORD i;
303 
304     for(i=0; i<This->sinks_size; i++) {
305         if(This->sinks[i].unk)
306             IUnknown_Release(This->sinks[i].unk);
307     }
308 
309     heap_free(This->sinks);
310 }
311 
312 static ConnectionPoint *get_cp(ConnectionPointContainer *container, REFIID riid, BOOL do_create)
313 {
314     const cpc_entry_t *iter;
315     unsigned idx, i;
316 
317     for(iter = container->cp_entries; iter->riid; iter++) {
318         if(IsEqualGUID(iter->riid, riid))
319             break;
320     }
321     if(!iter->riid)
322         return NULL;
323     idx = iter - container->cp_entries;
324 
325     if(!container->cps) {
326         if(!do_create)
327             return NULL;
328 
329         while(iter->riid)
330             iter++;
331         container->cps = heap_alloc((iter - container->cp_entries) * sizeof(*container->cps));
332         if(!container->cps)
333             return NULL;
334 
335         for(i=0; container->cp_entries[i].riid; i++)
336             ConnectionPoint_Init(container->cps+i, container, container->cp_entries[i].riid, container->cp_entries[i].desc);
337     }
338 
339     return container->cps+idx;
340 }
341 
342 void call_property_onchanged(ConnectionPointContainer *container, DISPID dispid)
343 {
344     ConnectionPoint *cp;
345     DWORD i;
346 
347     cp = get_cp(container, &IID_IPropertyNotifySink, FALSE);
348     if(!cp)
349         return;
350 
351     for(i=0; i<cp->sinks_size; i++) {
352         if(cp->sinks[i].propnotif)
353             IPropertyNotifySink_OnChanged(cp->sinks[i].propnotif, dispid);
354     }
355 }
356 
357 static inline ConnectionPointContainer *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
358 {
359     return CONTAINING_RECORD(iface, ConnectionPointContainer, IConnectionPointContainer_iface);
360 }
361 
362 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
363                                                               REFIID riid, void **ppv)
364 {
365     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
366     return IUnknown_QueryInterface(This->outer, riid, ppv);
367 }
368 
369 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
370 {
371     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
372     return IUnknown_AddRef(This->outer);
373 }
374 
375 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
376 {
377     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
378     return IUnknown_Release(This->outer);
379 }
380 
381 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
382         IEnumConnectionPoints **ppEnum)
383 {
384     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
385     FIXME("(%p)->(%p)\n", This, ppEnum);
386     return E_NOTIMPL;
387 }
388 
389 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
390         REFIID riid, IConnectionPoint **ppCP)
391 {
392     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
393     ConnectionPoint *cp;
394 
395     TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppCP);
396 
397     if(This->forward_container)
398         return IConnectionPointContainer_FindConnectionPoint(&This->forward_container->IConnectionPointContainer_iface,
399                 riid, ppCP);
400 
401     cp = get_cp(This, riid, TRUE);
402     if(!cp) {
403         FIXME("unsupported riid %s\n", debugstr_mshtml_guid(riid));
404         *ppCP = NULL;
405         return CONNECT_E_NOCONNECTION;
406     }
407 
408     *ppCP = &cp->IConnectionPoint_iface;
409     IConnectionPoint_AddRef(*ppCP);
410     return S_OK;
411 }
412 
413 static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = {
414     ConnectionPointContainer_QueryInterface,
415     ConnectionPointContainer_AddRef,
416     ConnectionPointContainer_Release,
417     ConnectionPointContainer_EnumConnectionPoints,
418     ConnectionPointContainer_FindConnectionPoint
419 };
420 
421 void ConnectionPointContainer_Init(ConnectionPointContainer *This, IUnknown *outer, const cpc_entry_t *cp_entries)
422 {
423     This->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
424     This->cp_entries = cp_entries;
425     This->cps = NULL;
426     This->outer = outer;
427     This->forward_container = NULL;
428 }
429 
430 void ConnectionPointContainer_Destroy(ConnectionPointContainer *This)
431 {
432     unsigned i;
433 
434     if(!This->cps)
435         return;
436 
437     for(i=0; This->cp_entries[i].riid; i++)
438         ConnectionPoint_Destroy(This->cps+i);
439     heap_free(This->cps);
440 }
441