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 const IConnectionPointVtbl *lpvtbl; 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 static const IConnectionPointVtbl ConnectionPointImpl_VTable; 70 71 72 /************************************************************************ 73 * Implementation of IEnumConnections 74 */ 75 typedef struct EnumConnectionsImpl { 76 77 const IEnumConnectionsVtbl *lpvtbl; 78 79 LONG ref; 80 81 /* IUnknown of ConnectionPoint, used for ref counting */ 82 IUnknown *pUnk; 83 84 /* Connection Data */ 85 CONNECTDATA *pCD; 86 DWORD nConns; 87 88 /* Next connection to enumerate from */ 89 DWORD nCur; 90 91 } EnumConnectionsImpl; 92 93 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, 94 DWORD nSinks, 95 CONNECTDATA *pCD); 96 97 98 /************************************************************************ 99 * ConnectionPointImpl_Construct 100 */ 101 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk, 102 REFIID riid) 103 { 104 ConnectionPointImpl *Obj; 105 106 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); 107 Obj->lpvtbl = &ConnectionPointImpl_VTable; 108 Obj->Obj = pUnk; 109 Obj->ref = 1; 110 Obj->iid = *riid; 111 Obj->maxSinks = MAXSINKS; 112 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 113 sizeof(IUnknown*) * MAXSINKS); 114 Obj->nSinks = 0; 115 return Obj; 116 } 117 118 /************************************************************************ 119 * ConnectionPointImpl_Destroy 120 */ 121 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj) 122 { 123 DWORD i; 124 for(i = 0; i < Obj->maxSinks; i++) { 125 if(Obj->sinks[i]) { 126 IUnknown_Release(Obj->sinks[i]); 127 Obj->sinks[i] = NULL; 128 } 129 } 130 HeapFree(GetProcessHeap(), 0, Obj->sinks); 131 HeapFree(GetProcessHeap(), 0, Obj); 132 return; 133 } 134 135 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface); 136 /************************************************************************ 137 * ConnectionPointImpl_QueryInterface (IUnknown) 138 * 139 * See Windows documentation for more details on IUnknown methods. 140 */ 141 static HRESULT WINAPI ConnectionPointImpl_QueryInterface( 142 IConnectionPoint* iface, 143 REFIID riid, 144 void** ppvObject) 145 { 146 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 147 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); 148 149 /* 150 * Perform a sanity check on the parameters. 151 */ 152 if ( (This==0) || (ppvObject==0) ) 153 return E_INVALIDARG; 154 155 /* 156 * Initialize the return parameter. 157 */ 158 *ppvObject = 0; 159 160 /* 161 * Compare the riid with the interface IDs implemented by this object. 162 */ 163 if (IsEqualIID(&IID_IUnknown, riid)) 164 *ppvObject = This; 165 else if (IsEqualIID(&IID_IConnectionPoint, riid)) 166 *ppvObject = This; 167 168 /* 169 * Check that we obtained an interface. 170 */ 171 if ((*ppvObject)==0) 172 { 173 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); 174 return E_NOINTERFACE; 175 } 176 177 /* 178 * Query Interface always increases the reference count by one when it is 179 * successful 180 */ 181 ConnectionPointImpl_AddRef((IConnectionPoint*)This); 182 183 return S_OK; 184 } 185 186 187 /************************************************************************ 188 * ConnectionPointImpl_AddRef (IUnknown) 189 * 190 * See Windows documentation for more details on IUnknown methods. 191 */ 192 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface) 193 { 194 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 195 ULONG refCount = InterlockedIncrement(&This->ref); 196 197 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1); 198 199 return refCount; 200 } 201 202 /************************************************************************ 203 * ConnectionPointImpl_Release (IUnknown) 204 * 205 * See Windows documentation for more details on IUnknown methods. 206 */ 207 static ULONG WINAPI ConnectionPointImpl_Release( 208 IConnectionPoint* iface) 209 { 210 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 211 ULONG refCount = InterlockedDecrement(&This->ref); 212 213 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1); 214 215 /* 216 * If the reference count goes down to 0, perform suicide. 217 */ 218 if (!refCount) ConnectionPointImpl_Destroy(This); 219 220 return refCount; 221 } 222 223 /************************************************************************ 224 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint) 225 * 226 */ 227 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface( 228 IConnectionPoint *iface, 229 IID *piid) 230 { 231 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 232 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid))); 233 *piid = This->iid; 234 return S_OK; 235 } 236 237 /************************************************************************ 238 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint) 239 * 240 */ 241 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer( 242 IConnectionPoint *iface, 243 IConnectionPointContainer **ppCPC) 244 { 245 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 246 TRACE("(%p)->(%p)\n", This, ppCPC); 247 248 return IUnknown_QueryInterface(This->Obj, 249 &IID_IConnectionPointContainer, 250 (LPVOID)ppCPC); 251 } 252 253 /************************************************************************ 254 * ConnectionPointImpl_Advise (IConnectionPoint) 255 * 256 */ 257 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface, 258 IUnknown *lpUnk, 259 DWORD *pdwCookie) 260 { 261 DWORD i; 262 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 263 IUnknown *lpSink; 264 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie); 265 266 *pdwCookie = 0; 267 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink))) 268 return CONNECT_E_CANNOTCONNECT; 269 270 for(i = 0; i < This->maxSinks; i++) { 271 if(This->sinks[i] == NULL) 272 break; 273 } 274 if(i == This->maxSinks) { 275 This->maxSinks += MAXSINKS; 276 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks, 277 This->maxSinks * sizeof(IUnknown *)); 278 } 279 This->sinks[i] = lpSink; 280 This->nSinks++; 281 *pdwCookie = i + 1; 282 return S_OK; 283 } 284 285 286 /************************************************************************ 287 * ConnectionPointImpl_Unadvise (IConnectionPoint) 288 * 289 */ 290 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface, 291 DWORD dwCookie) 292 { 293 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 294 TRACE("(%p)->(%d)\n", This, dwCookie); 295 296 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG; 297 298 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION; 299 300 IUnknown_Release(This->sinks[dwCookie-1]); 301 This->sinks[dwCookie-1] = NULL; 302 This->nSinks--; 303 return S_OK; 304 } 305 306 /************************************************************************ 307 * ConnectionPointImpl_EnumConnections (IConnectionPoint) 308 * 309 */ 310 static HRESULT WINAPI ConnectionPointImpl_EnumConnections( 311 IConnectionPoint *iface, 312 LPENUMCONNECTIONS *ppEnum) 313 { 314 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 315 CONNECTDATA *pCD; 316 DWORD i, nextslot; 317 EnumConnectionsImpl *EnumObj; 318 HRESULT hr; 319 320 TRACE("(%p)->(%p)\n", This, ppEnum); 321 322 *ppEnum = NULL; 323 324 if(This->nSinks == 0) return OLE_E_NOCONNECTION; 325 326 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks); 327 328 for(i = 0, nextslot = 0; i < This->maxSinks; i++) { 329 if(This->sinks[i] != NULL) { 330 pCD[nextslot].pUnk = This->sinks[i]; 331 pCD[nextslot].dwCookie = i + 1; 332 nextslot++; 333 } 334 } 335 assert(nextslot == This->nSinks); 336 337 /* Bump the ref count of this object up by one. It gets Released in 338 IEnumConnections_Release */ 339 IUnknown_AddRef((IUnknown*)This); 340 341 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD); 342 hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj, 343 &IID_IEnumConnections, (LPVOID)ppEnum); 344 IEnumConnections_Release((IEnumConnections*)EnumObj); 345 346 HeapFree(GetProcessHeap(), 0, pCD); 347 return hr; 348 } 349 350 static const IConnectionPointVtbl ConnectionPointImpl_VTable = 351 { 352 ConnectionPointImpl_QueryInterface, 353 ConnectionPointImpl_AddRef, 354 ConnectionPointImpl_Release, 355 ConnectionPointImpl_GetConnectionInterface, 356 ConnectionPointImpl_GetConnectionPointContainer, 357 ConnectionPointImpl_Advise, 358 ConnectionPointImpl_Unadvise, 359 ConnectionPointImpl_EnumConnections 360 }; 361 362 363 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable; 364 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface); 365 366 /************************************************************************ 367 * EnumConnectionsImpl_Construct 368 */ 369 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, 370 DWORD nSinks, 371 CONNECTDATA *pCD) 372 { 373 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); 374 DWORD i; 375 376 Obj->lpvtbl = &EnumConnectionsImpl_VTable; 377 Obj->ref = 1; 378 Obj->pUnk = pUnk; 379 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA)); 380 Obj->nConns = nSinks; 381 Obj->nCur = 0; 382 383 for(i = 0; i < nSinks; i++) { 384 Obj->pCD[i] = pCD[i]; 385 IUnknown_AddRef(Obj->pCD[i].pUnk); 386 } 387 return Obj; 388 } 389 390 /************************************************************************ 391 * EnumConnectionsImpl_Destroy 392 */ 393 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj) 394 { 395 DWORD i; 396 397 for(i = 0; i < Obj->nConns; i++) 398 IUnknown_Release(Obj->pCD[i].pUnk); 399 400 HeapFree(GetProcessHeap(), 0, Obj->pCD); 401 HeapFree(GetProcessHeap(), 0, Obj); 402 return; 403 } 404 405 /************************************************************************ 406 * EnumConnectionsImpl_QueryInterface (IUnknown) 407 * 408 * See Windows documentation for more details on IUnknown methods. 409 */ 410 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface( 411 IEnumConnections* iface, 412 REFIID riid, 413 void** ppvObject) 414 { 415 ConnectionPointImpl *This = (ConnectionPointImpl *)iface; 416 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); 417 418 /* 419 * Perform a sanity check on the parameters. 420 */ 421 if ( (This==0) || (ppvObject==0) ) 422 return E_INVALIDARG; 423 424 /* 425 * Initialize the return parameter. 426 */ 427 *ppvObject = 0; 428 429 /* 430 * Compare the riid with the interface IDs implemented by this object. 431 */ 432 if (IsEqualIID(&IID_IUnknown, riid)) 433 *ppvObject = This; 434 else if (IsEqualIID(&IID_IEnumConnections, riid)) 435 *ppvObject = This; 436 437 /* 438 * Check that we obtained an interface. 439 */ 440 if ((*ppvObject)==0) 441 { 442 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); 443 return E_NOINTERFACE; 444 } 445 446 /* 447 * Query Interface always increases the reference count by one when it is 448 * successful 449 */ 450 EnumConnectionsImpl_AddRef((IEnumConnections*)This); 451 452 return S_OK; 453 } 454 455 456 /************************************************************************ 457 * EnumConnectionsImpl_AddRef (IUnknown) 458 * 459 * See Windows documentation for more details on IUnknown methods. 460 */ 461 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface) 462 { 463 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; 464 ULONG refCount = InterlockedIncrement(&This->ref); 465 466 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1); 467 468 IUnknown_AddRef(This->pUnk); 469 return refCount; 470 } 471 472 /************************************************************************ 473 * EnumConnectionsImpl_Release (IUnknown) 474 * 475 * See Windows documentation for more details on IUnknown methods. 476 */ 477 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface) 478 { 479 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; 480 ULONG refCount = InterlockedDecrement(&This->ref); 481 482 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1); 483 484 IUnknown_Release(This->pUnk); 485 486 /* 487 * If the reference count goes down to 0, perform suicide. 488 */ 489 if (!refCount) EnumConnectionsImpl_Destroy(This); 490 491 return refCount; 492 } 493 494 /************************************************************************ 495 * EnumConnectionsImpl_Next (IEnumConnections) 496 * 497 */ 498 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface, 499 ULONG cConn, LPCONNECTDATA pCD, 500 ULONG *pEnum) 501 { 502 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; 503 DWORD nRet = 0; 504 TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum); 505 506 if(pEnum == NULL) { 507 if(cConn != 1) 508 return E_POINTER; 509 } else 510 *pEnum = 0; 511 512 if(This->nCur >= This->nConns) 513 return S_FALSE; 514 515 while(This->nCur < This->nConns && cConn) { 516 *pCD++ = This->pCD[This->nCur]; 517 IUnknown_AddRef(This->pCD[This->nCur].pUnk); 518 This->nCur++; 519 cConn--; 520 nRet++; 521 } 522 523 if(pEnum) 524 *pEnum = nRet; 525 526 return S_OK; 527 } 528 529 530 /************************************************************************ 531 * EnumConnectionsImpl_Skip (IEnumConnections) 532 * 533 */ 534 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface, 535 ULONG cSkip) 536 { 537 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; 538 TRACE("(%p)->(%d)\n", This, cSkip); 539 540 if(This->nCur + cSkip >= This->nConns) 541 return S_FALSE; 542 543 This->nCur += cSkip; 544 545 return S_OK; 546 } 547 548 549 /************************************************************************ 550 * EnumConnectionsImpl_Reset (IEnumConnections) 551 * 552 */ 553 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface) 554 { 555 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; 556 TRACE("(%p)\n", This); 557 558 This->nCur = 0; 559 560 return S_OK; 561 } 562 563 564 /************************************************************************ 565 * EnumConnectionsImpl_Clone (IEnumConnections) 566 * 567 */ 568 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface, 569 LPENUMCONNECTIONS *ppEnum) 570 { 571 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; 572 EnumConnectionsImpl *newObj; 573 TRACE("(%p)->(%p)\n", This, ppEnum); 574 575 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD); 576 newObj->nCur = This->nCur; 577 *ppEnum = (LPENUMCONNECTIONS)newObj; 578 IUnknown_AddRef(This->pUnk); 579 return S_OK; 580 } 581 582 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable = 583 { 584 EnumConnectionsImpl_QueryInterface, 585 EnumConnectionsImpl_AddRef, 586 EnumConnectionsImpl_Release, 587 EnumConnectionsImpl_Next, 588 EnumConnectionsImpl_Skip, 589 EnumConnectionsImpl_Reset, 590 EnumConnectionsImpl_Clone 591 }; 592 593 /************************************************************************ 594 * 595 * The exported function to create the connection point. 596 * NB not a windows API 597 * 598 * PARAMS 599 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated. 600 * Needed to access IConnectionPointContainer. 601 * 602 * riid [in] IID of sink interface that this ConnectionPoint manages 603 * 604 * pCP [out] returns IConnectionPoint 605 * 606 */ 607 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, 608 IConnectionPoint **pCP) 609 { 610 ConnectionPointImpl *Obj; 611 HRESULT hr; 612 613 Obj = ConnectionPointImpl_Construct(pUnk, riid); 614 if(!Obj) return E_OUTOFMEMORY; 615 616 hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj, 617 &IID_IConnectionPoint, (LPVOID)pCP); 618 IConnectionPoint_Release((IConnectionPoint *)Obj); 619 return hr; 620 } 621