d2d1: Add a helper to set error state.
[wine.git] / dlls / mshtml / conpoint.c
blobe959a0200738de08ddd7492dea422e16b598897f
1 /*
2 * Copyright 2006 Jacek Caban for CodeWeavers
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.
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.
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
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34 typedef struct {
35 IEnumConnections IEnumConnections_iface;
37 LONG ref;
39 unsigned iter;
40 ConnectionPoint *cp;
41 } EnumConnections;
43 static inline EnumConnections *impl_from_IEnumConnections(IEnumConnections *iface)
45 return CONTAINING_RECORD(iface, EnumConnections, IEnumConnections_iface);
48 static HRESULT WINAPI EnumConnections_QueryInterface(IEnumConnections *iface, REFIID riid, void **ppv)
50 EnumConnections *This = impl_from_IEnumConnections(iface);
52 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
54 if(IsEqualGUID(riid, &IID_IUnknown)) {
55 *ppv = &This->IEnumConnections_iface;
56 }else if(IsEqualGUID(riid, &IID_IEnumConnections)) {
57 *ppv = &This->IEnumConnections_iface;
58 }else {
59 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
60 *ppv = NULL;
61 return E_NOINTERFACE;
64 IUnknown_AddRef((IUnknown*)*ppv);
65 return S_OK;
68 static ULONG WINAPI EnumConnections_AddRef(IEnumConnections *iface)
70 EnumConnections *This = impl_from_IEnumConnections(iface);
71 ULONG ref = InterlockedIncrement(&This->ref);
73 TRACE("(%p) ref=%d\n", This, ref);
75 return ref;
78 static ULONG WINAPI EnumConnections_Release(IEnumConnections *iface)
80 EnumConnections *This = impl_from_IEnumConnections(iface);
81 ULONG ref = InterlockedDecrement(&This->ref);
83 TRACE("(%p) ref=%d\n", This, ref);
85 if(!ref) {
86 IConnectionPoint_Release(&This->cp->IConnectionPoint_iface);
87 heap_free(This);
90 return ref;
93 static HRESULT WINAPI EnumConnections_Next(IEnumConnections *iface, ULONG cConnections, CONNECTDATA *rgcd, ULONG *pcFetched)
95 EnumConnections *This = impl_from_IEnumConnections(iface);
96 ULONG fetched = 0;
98 TRACE("(%p)->(%d %p %p)\n", This, cConnections, rgcd, pcFetched);
100 while(fetched < cConnections && This->iter < This->cp->sinks_size) {
101 if(!This->cp->sinks[This->iter].unk) {
102 This->iter++;
103 continue;
106 rgcd[fetched].pUnk = This->cp->sinks[This->iter].unk;
107 rgcd[fetched].dwCookie = ++This->iter;
108 IUnknown_AddRef(rgcd[fetched].pUnk);
109 fetched++;
112 if(pcFetched)
113 *pcFetched = fetched;
114 return fetched == cConnections ? S_OK : S_FALSE;
117 static HRESULT WINAPI EnumConnections_Skip(IEnumConnections *iface, ULONG cConnections)
119 EnumConnections *This = impl_from_IEnumConnections(iface);
120 FIXME("(%p)->(%d)\n", This, cConnections);
121 return E_NOTIMPL;
124 static HRESULT WINAPI EnumConnections_Reset(IEnumConnections *iface)
126 EnumConnections *This = impl_from_IEnumConnections(iface);
127 FIXME("(%p)\n", This);
128 return E_NOTIMPL;
131 static HRESULT WINAPI EnumConnections_Clone(IEnumConnections *iface, IEnumConnections **ppEnum)
133 EnumConnections *This = impl_from_IEnumConnections(iface);
134 FIXME("(%p)->(%p)\n", This, ppEnum);
135 return E_NOTIMPL;
138 static const IEnumConnectionsVtbl EnumConnectionsVtbl = {
139 EnumConnections_QueryInterface,
140 EnumConnections_AddRef,
141 EnumConnections_Release,
142 EnumConnections_Next,
143 EnumConnections_Skip,
144 EnumConnections_Reset,
145 EnumConnections_Clone
148 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
150 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
153 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
154 REFIID riid, LPVOID *ppv)
156 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
158 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
160 if(IsEqualGUID(&IID_IUnknown, riid)) {
161 *ppv = &This->IConnectionPoint_iface;
162 }else if(IsEqualGUID(&IID_IConnectionPoint, riid)) {
163 *ppv = &This->IConnectionPoint_iface;
164 }else {
165 *ppv = NULL;
166 WARN("Unsupported interface %s\n", debugstr_mshtml_guid(riid));
167 return E_NOINTERFACE;
170 IUnknown_AddRef((IUnknown*)*ppv);
171 return S_OK;
174 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
176 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
177 return IConnectionPointContainer_AddRef(&This->container->IConnectionPointContainer_iface);
180 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
182 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
183 return IConnectionPointContainer_Release(&This->container->IConnectionPointContainer_iface);
186 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID)
188 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
190 TRACE("(%p)->(%p)\n", This, pIID);
192 if(!pIID)
193 return E_POINTER;
195 *pIID = *This->iid;
196 return S_OK;
199 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
200 IConnectionPointContainer **ppCPC)
202 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
204 TRACE("(%p)->(%p)\n", This, ppCPC);
206 if(!ppCPC)
207 return E_POINTER;
209 *ppCPC = &This->container->IConnectionPointContainer_iface;
210 IConnectionPointContainer_AddRef(*ppCPC);
211 return S_OK;
214 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
215 DWORD *pdwCookie)
217 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
218 IUnknown *sink;
219 DWORD i;
220 HRESULT hres;
222 TRACE("(%p)->(%p %p)\n", This, pUnkSink, pdwCookie);
224 hres = IUnknown_QueryInterface(pUnkSink, This->iid, (void**)&sink);
225 if(FAILED(hres) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
226 hres = IUnknown_QueryInterface(pUnkSink, &IID_IDispatch, (void**)&sink);
227 if(FAILED(hres))
228 return CONNECT_E_CANNOTCONNECT;
230 if(This->sinks) {
231 for(i=0; i<This->sinks_size; i++) {
232 if(!This->sinks[i].unk)
233 break;
236 if(i == This->sinks_size)
237 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
238 }else {
239 This->sinks = heap_alloc(sizeof(*This->sinks));
240 This->sinks_size = 1;
241 i = 0;
244 This->sinks[i].unk = sink;
245 if(pdwCookie)
246 *pdwCookie = i+1;
248 if(!i && This->data && This->data->on_advise)
249 This->data->on_advise(This->container->outer, This->data);
251 return S_OK;
254 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie)
256 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
257 TRACE("(%p)->(%d)\n", This, dwCookie);
259 if(!dwCookie || dwCookie > This->sinks_size || !This->sinks[dwCookie-1].unk)
260 return CONNECT_E_NOCONNECTION;
262 IUnknown_Release(This->sinks[dwCookie-1].unk);
263 This->sinks[dwCookie-1].unk = NULL;
265 return S_OK;
268 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
269 IEnumConnections **ppEnum)
271 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
272 EnumConnections *ret;
274 TRACE("(%p)->(%p)\n", This, ppEnum);
276 ret = heap_alloc(sizeof(*ret));
277 if(!ret)
278 return E_OUTOFMEMORY;
280 ret->IEnumConnections_iface.lpVtbl = &EnumConnectionsVtbl;
281 ret->ref = 1;
282 ret->iter = 0;
284 IConnectionPoint_AddRef(&This->IConnectionPoint_iface);
285 ret->cp = This;
287 *ppEnum = &ret->IEnumConnections_iface;
288 return S_OK;
291 static const IConnectionPointVtbl ConnectionPointVtbl =
293 ConnectionPoint_QueryInterface,
294 ConnectionPoint_AddRef,
295 ConnectionPoint_Release,
296 ConnectionPoint_GetConnectionInterface,
297 ConnectionPoint_GetConnectionPointContainer,
298 ConnectionPoint_Advise,
299 ConnectionPoint_Unadvise,
300 ConnectionPoint_EnumConnections
303 static void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid, cp_static_data_t *data)
305 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
306 cp->container = container;
307 cp->sinks = NULL;
308 cp->sinks_size = 0;
309 cp->iid = riid;
310 cp->data = data;
313 static void ConnectionPoint_Destroy(ConnectionPoint *This)
315 DWORD i;
317 for(i=0; i<This->sinks_size; i++) {
318 if(This->sinks[i].unk)
319 IUnknown_Release(This->sinks[i].unk);
322 heap_free(This->sinks);
325 static ConnectionPoint *get_cp(ConnectionPointContainer *container, REFIID riid, BOOL do_create)
327 const cpc_entry_t *iter;
328 unsigned idx, i;
330 for(iter = container->cp_entries; iter->riid; iter++) {
331 if(IsEqualGUID(iter->riid, riid))
332 break;
334 if(!iter->riid)
335 return NULL;
336 idx = iter - container->cp_entries;
338 if(!container->cps) {
339 if(!do_create)
340 return NULL;
342 while(iter->riid)
343 iter++;
344 container->cps = heap_alloc((iter - container->cp_entries) * sizeof(*container->cps));
345 if(!container->cps)
346 return NULL;
348 for(i=0; container->cp_entries[i].riid; i++)
349 ConnectionPoint_Init(container->cps+i, container, container->cp_entries[i].riid, container->cp_entries[i].desc);
352 return container->cps+idx;
355 void call_property_onchanged(ConnectionPointContainer *container, DISPID dispid)
357 ConnectionPoint *cp;
358 DWORD i;
360 cp = get_cp(container, &IID_IPropertyNotifySink, FALSE);
361 if(!cp)
362 return;
364 for(i=0; i<cp->sinks_size; i++) {
365 if(cp->sinks[i].propnotif)
366 IPropertyNotifySink_OnChanged(cp->sinks[i].propnotif, dispid);
370 static inline ConnectionPointContainer *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
372 return CONTAINING_RECORD(iface, ConnectionPointContainer, IConnectionPointContainer_iface);
375 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
376 REFIID riid, void **ppv)
378 ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
379 return IUnknown_QueryInterface(This->outer, riid, ppv);
382 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
384 ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
385 return IUnknown_AddRef(This->outer);
388 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
390 ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
391 return IUnknown_Release(This->outer);
394 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
395 IEnumConnectionPoints **ppEnum)
397 ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
398 FIXME("(%p)->(%p)\n", This, ppEnum);
399 return E_NOTIMPL;
402 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
403 REFIID riid, IConnectionPoint **ppCP)
405 ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
406 ConnectionPoint *cp;
408 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppCP);
410 if(This->forward_container)
411 return IConnectionPointContainer_FindConnectionPoint(&This->forward_container->IConnectionPointContainer_iface,
412 riid, ppCP);
414 cp = get_cp(This, riid, TRUE);
415 if(!cp) {
416 FIXME("unsupported riid %s\n", debugstr_mshtml_guid(riid));
417 *ppCP = NULL;
418 return CONNECT_E_NOCONNECTION;
421 *ppCP = &cp->IConnectionPoint_iface;
422 IConnectionPoint_AddRef(*ppCP);
423 return S_OK;
426 static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = {
427 ConnectionPointContainer_QueryInterface,
428 ConnectionPointContainer_AddRef,
429 ConnectionPointContainer_Release,
430 ConnectionPointContainer_EnumConnectionPoints,
431 ConnectionPointContainer_FindConnectionPoint
434 void ConnectionPointContainer_Init(ConnectionPointContainer *This, IUnknown *outer, const cpc_entry_t *cp_entries)
436 This->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
437 This->cp_entries = cp_entries;
438 This->cps = NULL;
439 This->outer = outer;
440 This->forward_container = NULL;
443 void ConnectionPointContainer_Destroy(ConnectionPointContainer *This)
445 unsigned i;
447 if(!This->cps)
448 return;
450 for(i=0; This->cp_entries[i].riid; i++)
451 ConnectionPoint_Destroy(This->cps+i);
452 heap_free(This->cps);