1 /* 2 * Implementation of a generic ConnectionPoint object. 3 * 4 * Copyright 2000 Huw D M Davies for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 * NOTES: 21 * See one exported function here is CreateConnectionPoint, see 22 * comments just above that function for information. 23 */ 24 25 #include <assert.h> 26 #include <stdarg.h> 27 #include <string.h> 28 29 #define COBJMACROS 30 31 #include "winerror.h" 32 #include "windef.h" 33 #include "winbase.h" 34 #include "wingdi.h" 35 #include "winuser.h" 36 #include "ole2.h" 37 #include "olectl.h" 38 #include "connpt.h" 39 40 #include "wine/debug.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(ole); 43 44 #define MAXSINKS 10 45 46 /************************************************************************ 47 * Implementation of IConnectionPoint 48 */ 49 typedef struct ConnectionPointImpl { 50 51 IConnectionPoint IConnectionPoint_iface; 52 53 /* IUnknown of our main object*/ 54 IUnknown *Obj; 55 56 /* Reference count */ 57 LONG ref; 58 59 /* IID of sink interface */ 60 IID iid; 61 62 /* Array of sink IUnknowns */ 63 IUnknown **sinks; 64 DWORD maxSinks; 65 66 DWORD nSinks; 67 } ConnectionPointImpl; 68 69 /************************************************************************ 70 * Implementation of IEnumConnections 71 */ 72 typedef struct EnumConnectionsImpl { 73 74 IEnumConnections IEnumConnections_iface; 75 76 LONG ref; 77 78 /* IUnknown of ConnectionPoint, used for ref counting */ 79 IUnknown *pUnk; 80 81 /* Connection Data */ 82 CONNECTDATA *pCD; 83 DWORD nConns; 84 85 /* Next connection to enumerate from */ 86 DWORD nCur; 87 88 } EnumConnectionsImpl; 89 90 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, 91 DWORD nSinks, 92 CONNECTDATA *pCD); 93 94 static inline ConnectionPointImpl *impl_from_IConnectionPoint(IConnectionPoint *iface) 95 { 96 return CONTAINING_RECORD(iface, ConnectionPointImpl, IConnectionPoint_iface); 97 } 98 99 static inline EnumConnectionsImpl *impl_from_IEnumConnections(IEnumConnections *iface) 100 { 101 return CONTAINING_RECORD(iface, EnumConnectionsImpl, IEnumConnections_iface); 102 } 103 104 /************************************************************************ 105 * ConnectionPointImpl_Destroy 106 */ 107 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj) 108 { 109 DWORD i; 110 for(i = 0; i < Obj->maxSinks; i++) { 111 if(Obj->sinks[i]) { 112 IUnknown_Release(Obj->sinks[i]); 113 Obj->sinks[i] = NULL; 114 } 115 } 116 HeapFree(GetProcessHeap(), 0, Obj->sinks); 117 HeapFree(GetProcessHeap(), 0, Obj); 118 return; 119 } 120 121 /************************************************************************ 122 * ConnectionPointImpl_QueryInterface (IUnknown) 123 * 124 * See Windows documentation for more details on IUnknown methods. 125 */ 126 static HRESULT WINAPI ConnectionPointImpl_QueryInterface( 127 IConnectionPoint* iface, 128 REFIID riid, 129 void** ppvObject) 130 { 131 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 132 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); 133 134 /* 135 * Perform a sanity check on the parameters. 136 */ 137 if (!ppvObject) 138 return E_INVALIDARG; 139 140 /* 141 * Initialize the return parameter. 142 */ 143 *ppvObject = 0; 144 145 146 if (IsEqualIID(&IID_IConnectionPoint, riid) || IsEqualIID(&IID_IUnknown, riid)) 147 *ppvObject = iface; 148 149 /* 150 * Check that we obtained an interface. 151 */ 152 if ((*ppvObject)==0) 153 { 154 FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid)); 155 return E_NOINTERFACE; 156 } 157 158 IUnknown_AddRef((IUnknown*)*ppvObject); 159 160 return S_OK; 161 } 162 163 164 /************************************************************************ 165 * ConnectionPointImpl_AddRef (IUnknown) 166 * 167 * See Windows documentation for more details on IUnknown methods. 168 */ 169 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface) 170 { 171 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 172 ULONG refCount = InterlockedIncrement(&This->ref); 173 174 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1); 175 176 return refCount; 177 } 178 179 /************************************************************************ 180 * ConnectionPointImpl_Release (IUnknown) 181 * 182 * See Windows documentation for more details on IUnknown methods. 183 */ 184 static ULONG WINAPI ConnectionPointImpl_Release( 185 IConnectionPoint* iface) 186 { 187 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 188 ULONG refCount = InterlockedDecrement(&This->ref); 189 190 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1); 191 192 /* 193 * If the reference count goes down to 0, perform suicide. 194 */ 195 if (!refCount) ConnectionPointImpl_Destroy(This); 196 197 return refCount; 198 } 199 200 /************************************************************************ 201 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint) 202 * 203 */ 204 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface( 205 IConnectionPoint *iface, 206 IID *piid) 207 { 208 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 209 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid))); 210 *piid = This->iid; 211 return S_OK; 212 } 213 214 /************************************************************************ 215 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint) 216 * 217 */ 218 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer( 219 IConnectionPoint *iface, 220 IConnectionPointContainer **ppCPC) 221 { 222 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 223 TRACE("(%p)->(%p)\n", This, ppCPC); 224 225 return IUnknown_QueryInterface(This->Obj, &IID_IConnectionPointContainer, (void**)ppCPC); 226 } 227 228 /************************************************************************ 229 * ConnectionPointImpl_Advise (IConnectionPoint) 230 * 231 */ 232 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface, 233 IUnknown *lpUnk, 234 DWORD *pdwCookie) 235 { 236 DWORD i; 237 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 238 IUnknown *lpSink; 239 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie); 240 241 *pdwCookie = 0; 242 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (void**)&lpSink))) 243 return CONNECT_E_CANNOTCONNECT; 244 245 for(i = 0; i < This->maxSinks; i++) { 246 if(This->sinks[i] == NULL) 247 break; 248 } 249 if(i == This->maxSinks) { 250 This->maxSinks += MAXSINKS; 251 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks, 252 This->maxSinks * sizeof(IUnknown *)); 253 } 254 This->sinks[i] = lpSink; 255 This->nSinks++; 256 *pdwCookie = i + 1; 257 return S_OK; 258 } 259 260 261 /************************************************************************ 262 * ConnectionPointImpl_Unadvise (IConnectionPoint) 263 * 264 */ 265 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface, 266 DWORD dwCookie) 267 { 268 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 269 TRACE("(%p)->(%d)\n", This, dwCookie); 270 271 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG; 272 273 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION; 274 275 IUnknown_Release(This->sinks[dwCookie-1]); 276 This->sinks[dwCookie-1] = NULL; 277 This->nSinks--; 278 return S_OK; 279 } 280 281 /************************************************************************ 282 * ConnectionPointImpl_EnumConnections (IConnectionPoint) 283 * 284 */ 285 static HRESULT WINAPI ConnectionPointImpl_EnumConnections( 286 IConnectionPoint *iface, 287 LPENUMCONNECTIONS *ppEnum) 288 { 289 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface); 290 CONNECTDATA *pCD; 291 DWORD i, nextslot; 292 EnumConnectionsImpl *EnumObj; 293 HRESULT hr; 294 295 TRACE("(%p)->(%p)\n", This, ppEnum); 296 297 *ppEnum = NULL; 298 299 if(This->nSinks == 0) return OLE_E_NOCONNECTION; 300 301 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks); 302 303 for(i = 0, nextslot = 0; i < This->maxSinks; i++) { 304 if(This->sinks[i] != NULL) { 305 pCD[nextslot].pUnk = This->sinks[i]; 306 pCD[nextslot].dwCookie = i + 1; 307 nextslot++; 308 } 309 } 310 assert(nextslot == This->nSinks); 311 312 /* Bump the ref count of this object up by one. It gets Released in 313 IEnumConnections_Release */ 314 IConnectionPoint_AddRef(iface); 315 316 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)iface, This->nSinks, pCD); 317 hr = IEnumConnections_QueryInterface(&EnumObj->IEnumConnections_iface, 318 &IID_IEnumConnections, (void**)ppEnum); 319 IEnumConnections_Release(&EnumObj->IEnumConnections_iface); 320 321 HeapFree(GetProcessHeap(), 0, pCD); 322 return hr; 323 } 324 325 static const IConnectionPointVtbl ConnectionPointImpl_VTable = 326 { 327 ConnectionPointImpl_QueryInterface, 328 ConnectionPointImpl_AddRef, 329 ConnectionPointImpl_Release, 330 ConnectionPointImpl_GetConnectionInterface, 331 ConnectionPointImpl_GetConnectionPointContainer, 332 ConnectionPointImpl_Advise, 333 ConnectionPointImpl_Unadvise, 334 ConnectionPointImpl_EnumConnections 335 }; 336 337 338 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable; 339 340 /************************************************************************ 341 * EnumConnectionsImpl_Construct 342 */ 343 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, 344 DWORD nSinks, 345 CONNECTDATA *pCD) 346 { 347 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); 348 DWORD i; 349 350 Obj->IEnumConnections_iface.lpVtbl = &EnumConnectionsImpl_VTable; 351 Obj->ref = 1; 352 Obj->pUnk = pUnk; 353 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA)); 354 Obj->nConns = nSinks; 355 Obj->nCur = 0; 356 357 for(i = 0; i < nSinks; i++) { 358 Obj->pCD[i] = pCD[i]; 359 IUnknown_AddRef(Obj->pCD[i].pUnk); 360 } 361 return Obj; 362 } 363 364 /************************************************************************ 365 * EnumConnectionsImpl_Destroy 366 */ 367 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj) 368 { 369 DWORD i; 370 371 for(i = 0; i < Obj->nConns; i++) 372 IUnknown_Release(Obj->pCD[i].pUnk); 373 374 HeapFree(GetProcessHeap(), 0, Obj->pCD); 375 HeapFree(GetProcessHeap(), 0, Obj); 376 return; 377 } 378 379 /************************************************************************ 380 * EnumConnectionsImpl_QueryInterface (IUnknown) 381 * 382 * See Windows documentation for more details on IUnknown methods. 383 */ 384 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface( 385 IEnumConnections* iface, 386 REFIID riid, 387 void** ppvObject) 388 { 389 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 390 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); 391 392 /* 393 * Perform a sanity check on the parameters. 394 */ 395 if (!ppvObject) 396 return E_INVALIDARG; 397 398 /* 399 * Initialize the return parameter. 400 */ 401 *ppvObject = 0; 402 403 if (IsEqualIID(&IID_IEnumConnections, riid) || IsEqualIID(&IID_IUnknown, riid)) 404 *ppvObject = iface; 405 406 /* 407 * Check that we obtained an interface. 408 */ 409 if ((*ppvObject)==0) 410 { 411 FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid)); 412 return E_NOINTERFACE; 413 } 414 415 IUnknown_AddRef((IUnknown*)*ppvObject); 416 417 return S_OK; 418 } 419 420 421 /************************************************************************ 422 * EnumConnectionsImpl_AddRef (IUnknown) 423 * 424 * See Windows documentation for more details on IUnknown methods. 425 */ 426 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface) 427 { 428 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface); 429 ULONG refCount = InterlockedIncrement(&This->ref); 430 431 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1); 432 433 IUnknown_AddRef(This->pUnk); 434 return refCount; 435 } 436 437 /************************************************************************ 438 * EnumConnectionsImpl_Release (IUnknown) 439 * 440 * See Windows documentation for more details on IUnknown methods. 441 */ 442 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface) 443 { 444 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface); 445 ULONG refCount = InterlockedDecrement(&This->ref); 446 447 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1); 448 449 IUnknown_Release(This->pUnk); 450 451 /* 452 * If the reference count goes down to 0, perform suicide. 453 */ 454 if (!refCount) EnumConnectionsImpl_Destroy(This); 455 456 return refCount; 457 } 458 459 /************************************************************************ 460 * EnumConnectionsImpl_Next (IEnumConnections) 461 * 462 */ 463 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface, 464 ULONG cConn, LPCONNECTDATA pCD, 465 ULONG *pEnum) 466 { 467 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface); 468 DWORD nRet = 0; 469 TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum); 470 471 if(pEnum == NULL) { 472 if(cConn != 1) 473 return E_POINTER; 474 } else 475 *pEnum = 0; 476 477 if(This->nCur >= This->nConns) 478 return S_FALSE; 479 480 while(This->nCur < This->nConns && cConn) { 481 *pCD++ = This->pCD[This->nCur]; 482 IUnknown_AddRef(This->pCD[This->nCur].pUnk); 483 This->nCur++; 484 cConn--; 485 nRet++; 486 } 487 488 if(pEnum) 489 *pEnum = nRet; 490 491 return S_OK; 492 } 493 494 495 /************************************************************************ 496 * EnumConnectionsImpl_Skip (IEnumConnections) 497 * 498 */ 499 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface, 500 ULONG cSkip) 501 { 502 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface); 503 TRACE("(%p)->(%d)\n", This, cSkip); 504 505 if(This->nCur + cSkip >= This->nConns) 506 return S_FALSE; 507 508 This->nCur += cSkip; 509 510 return S_OK; 511 } 512 513 514 /************************************************************************ 515 * EnumConnectionsImpl_Reset (IEnumConnections) 516 * 517 */ 518 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface) 519 { 520 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface); 521 TRACE("(%p)\n", This); 522 523 This->nCur = 0; 524 525 return S_OK; 526 } 527 528 529 /************************************************************************ 530 * EnumConnectionsImpl_Clone (IEnumConnections) 531 * 532 */ 533 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface, 534 LPENUMCONNECTIONS *ppEnum) 535 { 536 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface); 537 EnumConnectionsImpl *newObj; 538 TRACE("(%p)->(%p)\n", This, ppEnum); 539 540 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD); 541 newObj->nCur = This->nCur; 542 *ppEnum = &newObj->IEnumConnections_iface; 543 IUnknown_AddRef(This->pUnk); 544 return S_OK; 545 } 546 547 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable = 548 { 549 EnumConnectionsImpl_QueryInterface, 550 EnumConnectionsImpl_AddRef, 551 EnumConnectionsImpl_Release, 552 EnumConnectionsImpl_Next, 553 EnumConnectionsImpl_Skip, 554 EnumConnectionsImpl_Reset, 555 EnumConnectionsImpl_Clone 556 }; 557 558 /************************************************************************ 559 * 560 * The exported function to create the connection point. 561 * NB not a windows API 562 * 563 * PARAMS 564 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated. 565 * Needed to access IConnectionPointContainer. 566 * 567 * riid [in] IID of sink interface that this ConnectionPoint manages 568 * 569 * pCP [out] returns IConnectionPoint 570 * 571 */ 572 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, 573 IConnectionPoint **pCP) 574 { 575 ConnectionPointImpl *Obj; 576 577 TRACE("(%p %s %p)\n", pUnk, debugstr_guid(riid), pCP); 578 579 *pCP = NULL; 580 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); 581 if (!Obj) 582 return E_OUTOFMEMORY; 583 584 Obj->IConnectionPoint_iface.lpVtbl = &ConnectionPointImpl_VTable; 585 Obj->Obj = pUnk; 586 Obj->ref = 1; 587 Obj->iid = *riid; 588 Obj->maxSinks = MAXSINKS; 589 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IUnknown*) * MAXSINKS); 590 Obj->nSinks = 0; 591 592 *pCP = &Obj->IConnectionPoint_iface; 593 return S_OK; 594 } 595