mshtml: Return early from BindToDocument if possible.
[wine] / dlls / 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 <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29
30 #include "mshtml_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
33
34 static const char *debugstr_cp_guid(REFIID riid)
35 {
36 #define X(x) \
37     if(IsEqualGUID(riid, &x)) \
38         return #x
39
40     X(IID_IPropertyNotifySink);
41     X(DIID_HTMLDocumentEvents);
42     X(DIID_HTMLDocumentEvents2);
43     X(DIID_HTMLTableEvents);
44     X(DIID_HTMLTextContainerEvents);
45
46 #undef X
47
48     return debugstr_guid(riid);
49 }
50
51 void call_property_onchanged(ConnectionPoint *This, DISPID dispid)
52 {
53     DWORD i;
54
55     for(i=0; i<This->sinks_size; i++) {
56         if(This->sinks[i].propnotif)
57             IPropertyNotifySink_OnChanged(This->sinks[i].propnotif, dispid);
58     }
59 }
60
61 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
62 {
63     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
64 }
65
66 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
67                                                      REFIID riid, LPVOID *ppv)
68 {
69     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
70
71     *ppv = NULL;
72
73     if(IsEqualGUID(&IID_IUnknown, riid)) {
74         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
75         *ppv = &This->IConnectionPoint_iface;
76     }else if(IsEqualGUID(&IID_IConnectionPoint, riid)) {
77         TRACE("(%p)->(IID_IConnectionPoint %p)\n", This, ppv);
78         *ppv = &This->IConnectionPoint_iface;
79     }
80
81     if(*ppv) {
82         IUnknown_AddRef((IUnknown*)*ppv);
83         return S_OK;
84     }
85
86     WARN("Unsupported interface %s\n", debugstr_guid(riid));
87     return E_NOINTERFACE;
88 }
89
90 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
91 {
92     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
93     return IConnectionPointContainer_AddRef(&This->container->IConnectionPointContainer_iface);
94 }
95
96 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
97 {
98     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
99     return IConnectionPointContainer_Release(&This->container->IConnectionPointContainer_iface);
100 }
101
102 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID)
103 {
104     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
105
106     TRACE("(%p)->(%p)\n", This, pIID);
107
108     if(!pIID)
109         return E_POINTER;
110
111     *pIID = *This->iid;
112     return S_OK;
113 }
114
115 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
116         IConnectionPointContainer **ppCPC)
117 {
118     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
119
120     TRACE("(%p)->(%p)\n", This, ppCPC);
121
122     if(!ppCPC)
123         return E_POINTER;
124
125     *ppCPC = &This->container->IConnectionPointContainer_iface;
126     IConnectionPointContainer_AddRef(*ppCPC);
127     return S_OK;
128 }
129
130 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
131                                              DWORD *pdwCookie)
132 {
133     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
134     IUnknown *sink;
135     DWORD i;
136     HRESULT hres;
137
138     TRACE("(%p)->(%p %p)\n", This, pUnkSink, pdwCookie);
139
140     hres = IUnknown_QueryInterface(pUnkSink, This->iid, (void**)&sink);
141     if(FAILED(hres) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
142         hres = IUnknown_QueryInterface(pUnkSink, &IID_IDispatch, (void**)&sink);
143     if(FAILED(hres))
144         return CONNECT_E_CANNOTCONNECT;
145
146     if(This->sinks) {
147         for(i=0; i<This->sinks_size; i++) {
148             if(!This->sinks[i].unk)
149                 break;
150         }
151
152         if(i == This->sinks_size)
153             This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
154     }else {
155         This->sinks = heap_alloc(sizeof(*This->sinks));
156         This->sinks_size = 1;
157         i = 0;
158     }
159
160     This->sinks[i].unk = sink;
161     if(pdwCookie)
162         *pdwCookie = i+1;
163
164     if(!i && This->data && This->data->on_advise)
165         This->data->on_advise(This->container->outer, This->data);
166
167     return S_OK;
168 }
169
170 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie)
171 {
172     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
173     TRACE("(%p)->(%d)\n", This, dwCookie);
174
175     if(!dwCookie || dwCookie > This->sinks_size || !This->sinks[dwCookie-1].unk)
176         return CONNECT_E_NOCONNECTION;
177
178     IUnknown_Release(This->sinks[dwCookie-1].unk);
179     This->sinks[dwCookie-1].unk = NULL;
180
181     return S_OK;
182 }
183
184 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
185                                                       IEnumConnections **ppEnum)
186 {
187     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
188     FIXME("(%p)->(%p)\n", This, ppEnum);
189     return E_NOTIMPL;
190 }
191
192 static const IConnectionPointVtbl ConnectionPointVtbl =
193 {
194     ConnectionPoint_QueryInterface,
195     ConnectionPoint_AddRef,
196     ConnectionPoint_Release,
197     ConnectionPoint_GetConnectionInterface,
198     ConnectionPoint_GetConnectionPointContainer,
199     ConnectionPoint_Advise,
200     ConnectionPoint_Unadvise,
201     ConnectionPoint_EnumConnections
202 };
203
204 void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid, cp_static_data_t *data)
205 {
206     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
207     cp->container = container;
208     cp->sinks = NULL;
209     cp->sinks_size = 0;
210     cp->iid = riid;
211     cp->data = data;
212
213     cp->next = container->cp_list;
214     container->cp_list = cp;
215 }
216
217 static void ConnectionPoint_Destroy(ConnectionPoint *This)
218 {
219     DWORD i;
220
221     for(i=0; i<This->sinks_size; i++) {
222         if(This->sinks[i].unk)
223             IUnknown_Release(This->sinks[i].unk);
224     }
225
226     heap_free(This->sinks);
227 }
228
229 static inline ConnectionPointContainer *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
230 {
231     return CONTAINING_RECORD(iface, ConnectionPointContainer, IConnectionPointContainer_iface);
232 }
233
234 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
235                                                               REFIID riid, void **ppv)
236 {
237     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
238     return IUnknown_QueryInterface(This->outer, riid, ppv);
239 }
240
241 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
242 {
243     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
244     return IUnknown_AddRef(This->outer);
245 }
246
247 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
248 {
249     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
250     return IUnknown_Release(This->outer);
251 }
252
253 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
254         IEnumConnectionPoints **ppEnum)
255 {
256     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
257     FIXME("(%p)->(%p)\n", This, ppEnum);
258     return E_NOTIMPL;
259 }
260
261 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
262         REFIID riid, IConnectionPoint **ppCP)
263 {
264     ConnectionPointContainer *This = impl_from_IConnectionPointContainer(iface);
265     ConnectionPoint *iter;
266
267     TRACE("(%p)->(%s %p)\n", This, debugstr_cp_guid(riid), ppCP);
268
269     if(This->forward_container)
270         return IConnectionPointContainer_FindConnectionPoint(&This->forward_container->IConnectionPointContainer_iface,
271                 riid, ppCP);
272
273     *ppCP = NULL;
274
275     for(iter = This->cp_list; iter; iter = iter->next) {
276         if(IsEqualGUID(iter->iid, riid))
277             *ppCP = &iter->IConnectionPoint_iface;
278     }
279
280     if(*ppCP) {
281         IConnectionPoint_AddRef(*ppCP);
282         return S_OK;
283     }
284
285     FIXME("unsupported riid %s\n", debugstr_cp_guid(riid));
286     return CONNECT_E_NOCONNECTION;
287 }
288
289 static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = {
290     ConnectionPointContainer_QueryInterface,
291     ConnectionPointContainer_AddRef,
292     ConnectionPointContainer_Release,
293     ConnectionPointContainer_EnumConnectionPoints,
294     ConnectionPointContainer_FindConnectionPoint
295 };
296
297 void ConnectionPointContainer_Init(ConnectionPointContainer *This, IUnknown *outer)
298 {
299     This->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
300     This->cp_list = NULL;
301     This->outer = outer;
302 }
303
304 void ConnectionPointContainer_Destroy(ConnectionPointContainer *This)
305 {
306     ConnectionPoint *iter = This->cp_list;
307
308     while(iter) {
309         ConnectionPoint_Destroy(iter);
310         iter = iter->next;
311     }
312 }