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