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