mshtml: Added IHTMLWindow2::get_option implementation.
[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 void call_property_onchanged(ConnectionPoint *This, DISPID dispid)
40 {
41     DWORD i;
42
43     for(i=0; i<This->sinks_size; i++) {
44         if(This->sinks[i].propnotif)
45             IPropertyNotifySink_OnChanged(This->sinks[i].propnotif, dispid);
46     }
47 }
48
49 #define CONPOINT_THIS(iface) DEFINE_THIS(ConnectionPoint, ConnectionPoint, iface)
50
51 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
52                                                      REFIID riid, LPVOID *ppv)
53 {
54     ConnectionPoint *This = CONPOINT_THIS(iface);
55
56     *ppv = NULL;
57
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = CONPOINT(This);
61     }else if(IsEqualGUID(&IID_IConnectionPoint, riid)) {
62         TRACE("(%p)->(IID_IConnectionPoint %p)\n", This, ppv);
63         *ppv = CONPOINT(This);
64     }
65
66     if(*ppv) {
67         IUnknown_AddRef((IUnknown*)*ppv);
68         return S_OK;
69     }
70
71     WARN("Unsupported interface %s\n", debugstr_guid(riid));
72     return E_NOINTERFACE;
73 }
74
75 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
76 {
77     ConnectionPoint *This = CONPOINT_THIS(iface);
78     return IConnectionPointContainer_AddRef(This->container);
79 }
80
81 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
82 {
83     ConnectionPoint *This = CONPOINT_THIS(iface);
84     return IConnectionPointContainer_Release(This->container);
85 }
86
87 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID)
88 {
89     ConnectionPoint *This = CONPOINT_THIS(iface);
90
91     TRACE("(%p)->(%p)\n", This, pIID);
92
93     if(!pIID)
94         return E_POINTER;
95
96     memcpy(pIID, &This->iid, sizeof(IID));
97     return S_OK;
98 }
99
100 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
101         IConnectionPointContainer **ppCPC)
102 {
103     ConnectionPoint *This = CONPOINT_THIS(iface);
104
105     TRACE("(%p)->(%p)\n", This, ppCPC);
106
107     if(!ppCPC)
108         return E_POINTER;
109
110     *ppCPC = This->container;
111     IConnectionPointContainer_AddRef(*ppCPC);
112     return S_OK;
113 }
114
115 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
116                                              DWORD *pdwCookie)
117 {
118     ConnectionPoint *This = CONPOINT_THIS(iface);
119     IUnknown *sink;
120     DWORD i;
121     HRESULT hres;
122
123     TRACE("(%p)->(%p %p)\n", This, pUnkSink, pdwCookie);
124
125     hres = IUnknown_QueryInterface(pUnkSink, &This->iid, (void**)&sink);
126     if(FAILED(hres) && !IsEqualGUID(&IID_IPropertyNotifySink, &This->iid))
127         hres = IUnknown_QueryInterface(pUnkSink, &IID_IDispatch, (void**)&sink);
128     if(FAILED(hres))
129         return CONNECT_E_CANNOTCONNECT;
130
131     if(This->sinks) {
132         for(i=0; i<This->sinks_size; i++) {
133             if(!This->sinks[i].unk)
134                 break;
135         }
136
137         if(i == This->sinks_size)
138             This->sinks = mshtml_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
139     }else {
140         This->sinks = mshtml_alloc(sizeof(*This->sinks));
141         This->sinks_size = 1;
142         i = 0;
143     }
144
145     This->sinks[i].unk = sink;
146     *pdwCookie = i+1;
147
148     return S_OK;
149 }
150
151 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie)
152 {
153     ConnectionPoint *This = CONPOINT_THIS(iface);
154     TRACE("(%p)->(%d)\n", This, dwCookie);
155
156     if(!dwCookie || dwCookie > This->sinks_size || !This->sinks[dwCookie-1].unk)
157         return CONNECT_E_NOCONNECTION;
158
159     IUnknown_Release(This->sinks[dwCookie-1].unk);
160     This->sinks[dwCookie-1].unk = NULL;
161
162     return S_OK;
163 }
164
165 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
166                                                       IEnumConnections **ppEnum)
167 {
168     ConnectionPoint *This = CONPOINT_THIS(iface);
169     FIXME("(%p)->(%p)\n", This, ppEnum);
170     return E_NOTIMPL;
171 }
172
173 #undef CONPOINT_THIS
174
175 static const IConnectionPointVtbl ConnectionPointVtbl =
176 {
177     ConnectionPoint_QueryInterface,
178     ConnectionPoint_AddRef,
179     ConnectionPoint_Release,
180     ConnectionPoint_GetConnectionInterface,
181     ConnectionPoint_GetConnectionPointContainer,
182     ConnectionPoint_Advise,
183     ConnectionPoint_Unadvise,
184     ConnectionPoint_EnumConnections
185 };
186
187 void ConnectionPoint_Init(ConnectionPoint *cp, IConnectionPointContainer *container,
188         REFIID riid, ConnectionPoint *prev)
189 {
190     cp->lpConnectionPointVtbl = &ConnectionPointVtbl;
191     cp->container = container;
192     cp->sinks = NULL;
193     cp->sinks_size = 0;
194     cp->iid = *riid;
195     cp->next = NULL;
196
197     if(prev)
198         prev->next = cp;
199 }
200
201 static void ConnectionPoint_Destroy(ConnectionPoint *This)
202 {
203     int i;
204
205     for(i=0; i<This->sinks_size; i++) {
206         if(This->sinks[i].unk)
207             IUnknown_Release(This->sinks[i].unk);
208     }
209
210     mshtml_free(This->sinks);
211 }
212
213 #define CONPTCONT_THIS(iface) DEFINE_THIS(ConnectionPointContainer, ConnectionPointContainer, iface)
214
215 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
216                                                               REFIID riid, void **ppv)
217 {
218     ConnectionPointContainer *This = CONPTCONT_THIS(iface);
219     return IUnknown_QueryInterface(This->outer, riid, ppv);
220 }
221
222 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
223 {
224     ConnectionPointContainer *This = CONPTCONT_THIS(iface);
225     return IUnknown_AddRef(This->outer);
226 }
227
228 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
229 {
230     ConnectionPointContainer *This = CONPTCONT_THIS(iface);
231     return IUnknown_Release(This->outer);
232 }
233
234 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
235         IEnumConnectionPoints **ppEnum)
236 {
237     ConnectionPointContainer *This = CONPTCONT_THIS(iface);
238     FIXME("(%p)->(%p)\n", This, ppEnum);
239     return E_NOTIMPL;
240 }
241
242 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
243         REFIID riid, IConnectionPoint **ppCP)
244 {
245     ConnectionPointContainer *This = CONPTCONT_THIS(iface);
246     ConnectionPoint *iter;
247
248     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppCP);
249
250     *ppCP = NULL;
251
252     for(iter = This->cp_list; iter; iter = iter->next) {
253         if(IsEqualGUID(&iter->iid, riid))
254             *ppCP = CONPOINT(iter);
255     }
256
257     if(*ppCP) {
258         IConnectionPoint_AddRef(*ppCP);
259         return S_OK;
260     }
261
262     FIXME("unsupported riid %s\n", debugstr_guid(riid));
263     return CONNECT_E_NOCONNECTION;
264 }
265
266 static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = {
267     ConnectionPointContainer_QueryInterface,
268     ConnectionPointContainer_AddRef,
269     ConnectionPointContainer_Release,
270     ConnectionPointContainer_EnumConnectionPoints,
271     ConnectionPointContainer_FindConnectionPoint
272 };
273
274 #undef CONPTCONT_THIS
275
276 void ConnectionPointContainer_Init(ConnectionPointContainer *This, ConnectionPoint *cp_list,
277         IUnknown *outer)
278 {
279     This->lpConnectionPointContainerVtbl = &ConnectionPointContainerVtbl;
280     This->cp_list = cp_list;
281     This->outer = outer;
282 }
283
284 void ConnectionPointContainer_Destroy(ConnectionPointContainer *This)
285 {
286     ConnectionPoint *iter = This->cp_list;
287
288     while(iter) {
289         ConnectionPoint_Destroy(iter);
290         iter = iter->next;
291     }
292 }