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 } 441