Revert tree-restructure attempt: r66583, r66582, r66581, r66578, sauf ntdll changes...
[reactos.git] / reactos / dll / win32 / mshtml / conpoint.c
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 }