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