1 /* 2 * OLE2 COM objects 3 * 4 * Copyright 1998 Eric Kohl 5 * Copyright 1999 Francis Beaudet 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 23 #include <stdarg.h> 24 #include <string.h> 25 26 #define COBJMACROS 27 #define NONAMELESSUNION 28 29 #include "windef.h" 30 #include "winbase.h" 31 #include "winuser.h" 32 #include "winerror.h" 33 #include "wine/debug.h" 34 #include "ole2.h" 35 36 #include "compobj_private.h" 37 38 WINE_DEFAULT_DEBUG_CHANNEL(ole); 39 40 #define INITIAL_SINKS 10 41 42 static void release_statdata(STATDATA *data) 43 { 44 CoTaskMemFree(data->formatetc.ptd); 45 data->formatetc.ptd = NULL; 46 47 if(data->pAdvSink) 48 { 49 IAdviseSink_Release(data->pAdvSink); 50 data->pAdvSink = NULL; 51 } 52 } 53 54 static HRESULT copy_statdata(STATDATA *dst, const STATDATA *src) 55 { 56 HRESULT hr; 57 58 hr = copy_formatetc( &dst->formatetc, &src->formatetc ); 59 if (FAILED(hr)) return hr; 60 dst->advf = src->advf; 61 dst->pAdvSink = src->pAdvSink; 62 if (dst->pAdvSink) IAdviseSink_AddRef( dst->pAdvSink ); 63 dst->dwConnection = src->dwConnection; 64 return S_OK; 65 } 66 67 /************************************************************************** 68 * EnumSTATDATA Implementation 69 */ 70 71 typedef struct 72 { 73 IEnumSTATDATA IEnumSTATDATA_iface; 74 LONG ref; 75 76 ULONG index; 77 DWORD num_of_elems; 78 STATDATA *statdata; 79 IUnknown *holder; 80 } EnumSTATDATA; 81 82 static inline EnumSTATDATA *impl_from_IEnumSTATDATA(IEnumSTATDATA *iface) 83 { 84 return CONTAINING_RECORD(iface, EnumSTATDATA, IEnumSTATDATA_iface); 85 } 86 87 static HRESULT WINAPI EnumSTATDATA_QueryInterface(IEnumSTATDATA *iface, REFIID riid, void **ppv) 88 { 89 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 90 if (IsEqualIID(riid, &IID_IUnknown) || 91 IsEqualIID(riid, &IID_IEnumSTATDATA)) 92 { 93 IEnumSTATDATA_AddRef(iface); 94 *ppv = iface; 95 return S_OK; 96 } 97 return E_NOINTERFACE; 98 } 99 100 static ULONG WINAPI EnumSTATDATA_AddRef(IEnumSTATDATA *iface) 101 { 102 EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface); 103 TRACE("()\n"); 104 return InterlockedIncrement(&This->ref); 105 } 106 107 static ULONG WINAPI EnumSTATDATA_Release(IEnumSTATDATA *iface) 108 { 109 EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface); 110 LONG refs = InterlockedDecrement(&This->ref); 111 TRACE("()\n"); 112 if (!refs) 113 { 114 DWORD i; 115 for(i = 0; i < This->num_of_elems; i++) 116 release_statdata(This->statdata + i); 117 HeapFree(GetProcessHeap(), 0, This->statdata); 118 if (This->holder) IUnknown_Release(This->holder); 119 HeapFree(GetProcessHeap(), 0, This); 120 } 121 return refs; 122 } 123 124 static HRESULT WINAPI EnumSTATDATA_Next(IEnumSTATDATA *iface, ULONG num, LPSTATDATA data, 125 ULONG *fetched) 126 { 127 EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface); 128 DWORD count = 0; 129 HRESULT hr = S_OK; 130 131 TRACE("(%d, %p, %p)\n", num, data, fetched); 132 133 while(num--) 134 { 135 if (This->index >= This->num_of_elems) 136 { 137 hr = S_FALSE; 138 break; 139 } 140 141 copy_statdata(data + count, This->statdata + This->index); 142 143 count++; 144 This->index++; 145 } 146 147 if (fetched) *fetched = count; 148 149 return hr; 150 } 151 152 static HRESULT WINAPI EnumSTATDATA_Skip(IEnumSTATDATA *iface, ULONG num) 153 { 154 EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface); 155 156 TRACE("(%d)\n", num); 157 158 if(This->index + num >= This->num_of_elems) 159 { 160 This->index = This->num_of_elems; 161 return S_FALSE; 162 } 163 164 This->index += num; 165 return S_OK; 166 } 167 168 static HRESULT WINAPI EnumSTATDATA_Reset(IEnumSTATDATA *iface) 169 { 170 EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface); 171 172 TRACE("()\n"); 173 174 This->index = 0; 175 return S_OK; 176 } 177 178 static HRESULT WINAPI EnumSTATDATA_Clone(IEnumSTATDATA *iface, IEnumSTATDATA **ppenum) 179 { 180 EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface); 181 182 return EnumSTATDATA_Construct(This->holder, This->index, This->num_of_elems, This->statdata, 183 TRUE, ppenum); 184 } 185 186 static const IEnumSTATDATAVtbl EnumSTATDATA_VTable = 187 { 188 EnumSTATDATA_QueryInterface, 189 EnumSTATDATA_AddRef, 190 EnumSTATDATA_Release, 191 EnumSTATDATA_Next, 192 EnumSTATDATA_Skip, 193 EnumSTATDATA_Reset, 194 EnumSTATDATA_Clone 195 }; 196 197 HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data, 198 BOOL copy, IEnumSTATDATA **ppenum) 199 { 200 EnumSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 201 DWORD i, count; 202 203 if (!This) return E_OUTOFMEMORY; 204 205 This->IEnumSTATDATA_iface.lpVtbl = &EnumSTATDATA_VTable; 206 This->ref = 1; 207 This->index = index; 208 209 if (copy) 210 { 211 This->statdata = HeapAlloc(GetProcessHeap(), 0, array_len * sizeof(*This->statdata)); 212 if(!This->statdata) 213 { 214 HeapFree(GetProcessHeap(), 0, This); 215 return E_OUTOFMEMORY; 216 } 217 218 for(i = 0, count = 0; i < array_len; i++) 219 { 220 if(data[i].pAdvSink) 221 { 222 copy_statdata(This->statdata + count, data + i); 223 count++; 224 } 225 } 226 } 227 else 228 { 229 This->statdata = data; 230 count = array_len; 231 } 232 233 This->num_of_elems = count; 234 This->holder = holder; 235 if (holder) IUnknown_AddRef(holder); 236 *ppenum = &This->IEnumSTATDATA_iface; 237 return S_OK; 238 } 239 240 /************************************************************************** 241 * OleAdviseHolder Implementation 242 */ 243 typedef struct 244 { 245 IOleAdviseHolder IOleAdviseHolder_iface; 246 247 LONG ref; 248 249 DWORD max_cons; 250 STATDATA *connections; 251 } OleAdviseHolderImpl; 252 253 static inline OleAdviseHolderImpl *impl_from_IOleAdviseHolder(IOleAdviseHolder *iface) 254 { 255 return CONTAINING_RECORD(iface, OleAdviseHolderImpl, IOleAdviseHolder_iface); 256 } 257 258 /************************************************************************** 259 * OleAdviseHolderImpl_Destructor 260 */ 261 static void OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl *This) 262 { 263 DWORD index; 264 TRACE("%p\n", This); 265 266 for (index = 0; index < This->max_cons; index++) 267 { 268 if (This->connections[index].pAdvSink != NULL) 269 release_statdata(This->connections + index); 270 } 271 272 HeapFree(GetProcessHeap(), 0, This->connections); 273 HeapFree(GetProcessHeap(), 0, This); 274 } 275 276 /************************************************************************** 277 * OleAdviseHolderImpl_QueryInterface 278 */ 279 static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(IOleAdviseHolder *iface, 280 REFIID iid, void **obj) 281 { 282 OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface); 283 TRACE("(%p)->(%s,%p)\n",This, debugstr_guid(iid), obj); 284 285 if (obj == NULL) 286 return E_POINTER; 287 288 *obj = NULL; 289 290 if (IsEqualIID(iid, &IID_IUnknown) || 291 IsEqualIID(iid, &IID_IOleAdviseHolder)) 292 { 293 *obj = &This->IOleAdviseHolder_iface; 294 } 295 296 if(*obj == NULL) 297 return E_NOINTERFACE; 298 299 IUnknown_AddRef((IUnknown*)*obj); 300 301 return S_OK; 302 } 303 304 /****************************************************************************** 305 * OleAdviseHolderImpl_AddRef 306 */ 307 static ULONG WINAPI OleAdviseHolderImpl_AddRef(IOleAdviseHolder *iface) 308 { 309 OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface); 310 ULONG ref = InterlockedIncrement(&This->ref); 311 312 TRACE("(%p)->(ref=%d)\n", This, ref - 1); 313 314 return ref; 315 } 316 317 /****************************************************************************** 318 * OleAdviseHolderImpl_Release 319 */ 320 static ULONG WINAPI OleAdviseHolderImpl_Release(IOleAdviseHolder *iface) 321 { 322 OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface); 323 ULONG ref; 324 TRACE("(%p)->(ref=%d)\n", This, This->ref); 325 ref = InterlockedDecrement(&This->ref); 326 327 if (ref == 0) OleAdviseHolderImpl_Destructor(This); 328 329 return ref; 330 } 331 332 /****************************************************************************** 333 * OleAdviseHolderImpl_Advise 334 */ 335 static HRESULT WINAPI OleAdviseHolderImpl_Advise(IOleAdviseHolder *iface, 336 IAdviseSink *pAdvise, 337 DWORD *pdwConnection) 338 { 339 DWORD index; 340 OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface); 341 STATDATA new_conn; 342 static const FORMATETC empty_fmtetc = {0, NULL, 0, -1, 0}; 343 344 TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection); 345 346 if (pdwConnection==NULL) 347 return E_POINTER; 348 349 *pdwConnection = 0; 350 351 for (index = 0; index < This->max_cons; index++) 352 { 353 if (This->connections[index].pAdvSink == NULL) 354 break; 355 } 356 357 if (index == This->max_cons) 358 { 359 This->max_cons += INITIAL_SINKS; 360 This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->connections, 361 This->max_cons * sizeof(*This->connections)); 362 } 363 364 new_conn.pAdvSink = pAdvise; 365 new_conn.advf = 0; 366 new_conn.formatetc = empty_fmtetc; 367 new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */ 368 369 copy_statdata(This->connections + index, &new_conn); 370 371 *pdwConnection = new_conn.dwConnection; 372 373 return S_OK; 374 } 375 376 /****************************************************************************** 377 * OleAdviseHolderImpl_Unadvise 378 */ 379 static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(IOleAdviseHolder *iface, 380 DWORD dwConnection) 381 { 382 OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface); 383 DWORD index; 384 385 TRACE("(%p)->(%u)\n", This, dwConnection); 386 387 /* The connection number is 1 more than the index, see OleAdviseHolder_Advise */ 388 index = dwConnection - 1; 389 390 if (index >= This->max_cons || This->connections[index].pAdvSink == NULL) 391 return OLE_E_NOCONNECTION; 392 393 release_statdata(This->connections + index); 394 395 return S_OK; 396 } 397 398 /****************************************************************************** 399 * OleAdviseHolderImpl_EnumAdvise 400 */ 401 static HRESULT WINAPI OleAdviseHolderImpl_EnumAdvise(IOleAdviseHolder *iface, IEnumSTATDATA **enum_advise) 402 { 403 OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface); 404 IUnknown *unk; 405 HRESULT hr; 406 407 TRACE("(%p)->(%p)\n", This, enum_advise); 408 409 IOleAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk); 410 hr = EnumSTATDATA_Construct(unk, 0, This->max_cons, This->connections, TRUE, enum_advise); 411 IUnknown_Release(unk); 412 return hr; 413 } 414 415 /****************************************************************************** 416 * OleAdviseHolderImpl_SendOnRename 417 */ 418 static HRESULT WINAPI OleAdviseHolderImpl_SendOnRename(IOleAdviseHolder *iface, IMoniker *pmk) 419 { 420 IEnumSTATDATA *pEnum; 421 HRESULT hr; 422 423 TRACE("(%p)->(%p)\n", iface, pmk); 424 425 hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum); 426 if (SUCCEEDED(hr)) 427 { 428 STATDATA statdata; 429 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) 430 { 431 IAdviseSink_OnRename(statdata.pAdvSink, pmk); 432 433 IAdviseSink_Release(statdata.pAdvSink); 434 } 435 IEnumSTATDATA_Release(pEnum); 436 } 437 438 return hr; 439 } 440 441 /****************************************************************************** 442 * OleAdviseHolderImpl_SendOnSave 443 */ 444 static HRESULT WINAPI OleAdviseHolderImpl_SendOnSave(IOleAdviseHolder *iface) 445 { 446 IEnumSTATDATA *pEnum; 447 HRESULT hr; 448 449 TRACE("(%p)->()\n", iface); 450 451 hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum); 452 if (SUCCEEDED(hr)) 453 { 454 STATDATA statdata; 455 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) 456 { 457 IAdviseSink_OnSave(statdata.pAdvSink); 458 459 IAdviseSink_Release(statdata.pAdvSink); 460 } 461 IEnumSTATDATA_Release(pEnum); 462 } 463 464 return hr; 465 } 466 467 /****************************************************************************** 468 * OleAdviseHolderImpl_SendOnClose 469 */ 470 static HRESULT WINAPI OleAdviseHolderImpl_SendOnClose(IOleAdviseHolder *iface) 471 { 472 IEnumSTATDATA *pEnum; 473 HRESULT hr; 474 475 TRACE("(%p)->()\n", iface); 476 477 hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum); 478 if (SUCCEEDED(hr)) 479 { 480 STATDATA statdata; 481 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) 482 { 483 IAdviseSink_OnClose(statdata.pAdvSink); 484 485 IAdviseSink_Release(statdata.pAdvSink); 486 } 487 IEnumSTATDATA_Release(pEnum); 488 } 489 490 return hr; 491 } 492 493 /************************************************************************** 494 * OleAdviseHolderImpl_VTable 495 */ 496 static const IOleAdviseHolderVtbl oahvt = 497 { 498 OleAdviseHolderImpl_QueryInterface, 499 OleAdviseHolderImpl_AddRef, 500 OleAdviseHolderImpl_Release, 501 OleAdviseHolderImpl_Advise, 502 OleAdviseHolderImpl_Unadvise, 503 OleAdviseHolderImpl_EnumAdvise, 504 OleAdviseHolderImpl_SendOnRename, 505 OleAdviseHolderImpl_SendOnSave, 506 OleAdviseHolderImpl_SendOnClose 507 }; 508 509 /************************************************************************** 510 * OleAdviseHolderImpl_Constructor 511 */ 512 513 static IOleAdviseHolder *OleAdviseHolderImpl_Constructor(void) 514 { 515 OleAdviseHolderImpl* lpoah; 516 517 lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl)); 518 519 lpoah->IOleAdviseHolder_iface.lpVtbl = &oahvt; 520 lpoah->ref = 1; 521 lpoah->max_cons = INITIAL_SINKS; 522 lpoah->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 523 lpoah->max_cons * sizeof(*lpoah->connections)); 524 525 TRACE("returning %p\n", &lpoah->IOleAdviseHolder_iface); 526 return &lpoah->IOleAdviseHolder_iface; 527 } 528 529 /************************************************************************** 530 * DataAdviseHolder Implementation 531 */ 532 typedef struct 533 { 534 IDataAdviseHolder IDataAdviseHolder_iface; 535 536 LONG ref; 537 DWORD maxCons; 538 STATDATA* connections; 539 DWORD* remote_connections; 540 IDataObject* delegate; 541 } DataAdviseHolder; 542 543 /* this connection has also has been advised to the delegate data object */ 544 #define WINE_ADVF_REMOTE 0x80000000 545 546 static inline DataAdviseHolder *impl_from_IDataAdviseHolder(IDataAdviseHolder *iface) 547 { 548 return CONTAINING_RECORD(iface, DataAdviseHolder, IDataAdviseHolder_iface); 549 } 550 551 /****************************************************************************** 552 * DataAdviseHolder_Destructor 553 */ 554 static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy) 555 { 556 DWORD index; 557 TRACE("%p\n", ptrToDestroy); 558 559 for (index = 0; index < ptrToDestroy->maxCons; index++) 560 { 561 if (ptrToDestroy->connections[index].pAdvSink != NULL) 562 { 563 if (ptrToDestroy->delegate && 564 (ptrToDestroy->connections[index].advf & WINE_ADVF_REMOTE)) 565 IDataObject_DUnadvise(ptrToDestroy->delegate, 566 ptrToDestroy->remote_connections[index]); 567 568 release_statdata(ptrToDestroy->connections + index); 569 } 570 } 571 572 HeapFree(GetProcessHeap(), 0, ptrToDestroy->remote_connections); 573 HeapFree(GetProcessHeap(), 0, ptrToDestroy->connections); 574 HeapFree(GetProcessHeap(), 0, ptrToDestroy); 575 } 576 577 /************************************************************************ 578 * DataAdviseHolder_QueryInterface (IUnknown) 579 */ 580 static HRESULT WINAPI DataAdviseHolder_QueryInterface(IDataAdviseHolder *iface, 581 REFIID riid, void **ppvObject) 582 { 583 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 584 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); 585 586 if ( (This==0) || (ppvObject==0) ) 587 return E_INVALIDARG; 588 589 *ppvObject = 0; 590 591 if ( IsEqualIID(&IID_IUnknown, riid) || 592 IsEqualIID(&IID_IDataAdviseHolder, riid) ) 593 { 594 *ppvObject = iface; 595 } 596 597 if ((*ppvObject)==0) 598 { 599 return E_NOINTERFACE; 600 } 601 602 IUnknown_AddRef((IUnknown*)*ppvObject); 603 return S_OK; 604 } 605 606 /************************************************************************ 607 * DataAdviseHolder_AddRef (IUnknown) 608 */ 609 static ULONG WINAPI DataAdviseHolder_AddRef(IDataAdviseHolder *iface) 610 { 611 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 612 TRACE("(%p) (ref=%d)\n", This, This->ref); 613 return InterlockedIncrement(&This->ref); 614 } 615 616 /************************************************************************ 617 * DataAdviseHolder_Release (IUnknown) 618 */ 619 static ULONG WINAPI DataAdviseHolder_Release(IDataAdviseHolder *iface) 620 { 621 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 622 ULONG ref; 623 TRACE("(%p) (ref=%d)\n", This, This->ref); 624 625 ref = InterlockedDecrement(&This->ref); 626 if (ref==0) DataAdviseHolder_Destructor(This); 627 628 return ref; 629 } 630 631 /************************************************************************ 632 * DataAdviseHolder_Advise 633 * 634 */ 635 static HRESULT WINAPI DataAdviseHolder_Advise(IDataAdviseHolder *iface, 636 IDataObject *pDataObject, FORMATETC *pFetc, 637 DWORD advf, IAdviseSink *pAdvise, 638 DWORD *pdwConnection) 639 { 640 DWORD index; 641 STATDATA new_conn; 642 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 643 644 TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf, 645 pAdvise, pdwConnection); 646 647 if (pdwConnection==NULL) 648 return E_POINTER; 649 650 *pdwConnection = 0; 651 652 for (index = 0; index < This->maxCons; index++) 653 { 654 if (This->connections[index].pAdvSink == NULL) 655 break; 656 } 657 658 if (index == This->maxCons) 659 { 660 This->maxCons+=INITIAL_SINKS; 661 This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 662 This->connections, 663 This->maxCons * sizeof(*This->connections)); 664 This->remote_connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 665 This->remote_connections, 666 This->maxCons * sizeof(*This->remote_connections)); 667 } 668 669 new_conn.pAdvSink = pAdvise; 670 new_conn.advf = advf & ~WINE_ADVF_REMOTE; 671 new_conn.formatetc = *pFetc; 672 new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */ 673 674 copy_statdata(This->connections + index, &new_conn); 675 676 if (This->connections[index].pAdvSink != NULL) 677 { 678 /* if we are already connected advise the remote object */ 679 if (This->delegate) 680 { 681 HRESULT hr; 682 683 hr = IDataObject_DAdvise(This->delegate, &new_conn.formatetc, 684 new_conn.advf, new_conn.pAdvSink, 685 &This->remote_connections[index]); 686 if (FAILED(hr)) 687 { 688 IDataAdviseHolder_Unadvise(iface, new_conn.dwConnection); 689 return hr; 690 } 691 This->connections[index].advf |= WINE_ADVF_REMOTE; 692 } 693 else if(advf & ADVF_PRIMEFIRST) 694 /* only do this if we have no delegate, since in the above case the 695 * delegate will do the priming for us */ 696 IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf); 697 } 698 699 *pdwConnection = new_conn.dwConnection; 700 701 return S_OK; 702 } 703 704 /****************************************************************************** 705 * DataAdviseHolder_Unadvise 706 */ 707 static HRESULT WINAPI DataAdviseHolder_Unadvise(IDataAdviseHolder *iface, 708 DWORD dwConnection) 709 { 710 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 711 DWORD index; 712 TRACE("(%p)->(%u)\n", This, dwConnection); 713 714 /* The connection number is 1 more than the index, see DataAdviseHolder_Advise */ 715 index = dwConnection - 1; 716 717 if (index >= This->maxCons || This->connections[index].pAdvSink == NULL) 718 return OLE_E_NOCONNECTION; 719 720 if (This->delegate && This->connections[index].advf & WINE_ADVF_REMOTE) 721 { 722 IDataObject_DUnadvise(This->delegate, This->remote_connections[index]); 723 This->remote_connections[index] = 0; 724 } 725 726 release_statdata(This->connections + index); 727 728 return S_OK; 729 } 730 731 /****************************************************************************** 732 * DataAdviseHolder_EnumAdvise 733 */ 734 static HRESULT WINAPI DataAdviseHolder_EnumAdvise(IDataAdviseHolder *iface, 735 IEnumSTATDATA **enum_advise) 736 { 737 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 738 IUnknown *unk; 739 HRESULT hr; 740 741 TRACE("(%p)->(%p)\n", This, enum_advise); 742 743 IDataAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk); 744 hr = EnumSTATDATA_Construct(unk, 0, This->maxCons, This->connections, TRUE, enum_advise); 745 IUnknown_Release(unk); 746 return hr; 747 } 748 749 /****************************************************************************** 750 * DataAdviseHolder_SendOnDataChange 751 */ 752 static HRESULT WINAPI DataAdviseHolder_SendOnDataChange(IDataAdviseHolder *iface, 753 IDataObject *data_obj, 754 DWORD dwReserved, DWORD advf) 755 { 756 IEnumSTATDATA *pEnum; 757 HRESULT hr; 758 759 TRACE("(%p)->(%p, %08x, %08x)\n", iface, data_obj, dwReserved, advf); 760 761 hr = IDataAdviseHolder_EnumAdvise(iface, &pEnum); 762 if (SUCCEEDED(hr)) 763 { 764 STATDATA statdata; 765 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) 766 { 767 STGMEDIUM stg; 768 stg.tymed = TYMED_NULL; 769 stg.u.pstg = NULL; 770 stg.pUnkForRelease = NULL; 771 772 if(!(statdata.advf & ADVF_NODATA)) 773 { 774 hr = IDataObject_GetData(data_obj, &statdata.formatetc, &stg); 775 } 776 777 IAdviseSink_OnDataChange(statdata.pAdvSink, &statdata.formatetc, &stg); 778 779 if(statdata.advf & ADVF_ONLYONCE) 780 { 781 IDataAdviseHolder_Unadvise(iface, statdata.dwConnection); 782 } 783 784 release_statdata(&statdata); 785 } 786 IEnumSTATDATA_Release(pEnum); 787 } 788 789 return S_OK; 790 } 791 792 /************************************************************************** 793 * DataAdviseHolderImpl_VTable 794 */ 795 static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable = 796 { 797 DataAdviseHolder_QueryInterface, 798 DataAdviseHolder_AddRef, 799 DataAdviseHolder_Release, 800 DataAdviseHolder_Advise, 801 DataAdviseHolder_Unadvise, 802 DataAdviseHolder_EnumAdvise, 803 DataAdviseHolder_SendOnDataChange 804 }; 805 806 HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate) 807 { 808 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 809 DWORD index; 810 HRESULT hr = S_OK; 811 812 for(index = 0; index < This->maxCons; index++) 813 { 814 if(This->connections[index].pAdvSink != NULL) 815 { 816 hr = IDataObject_DAdvise(pDelegate, &This->connections[index].formatetc, 817 This->connections[index].advf, 818 This->connections[index].pAdvSink, 819 &This->remote_connections[index]); 820 if (FAILED(hr)) break; 821 This->connections[index].advf |= WINE_ADVF_REMOTE; 822 } 823 } 824 This->delegate = pDelegate; 825 return hr; 826 } 827 828 void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface) 829 { 830 DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface); 831 DWORD index; 832 833 for(index = 0; index < This->maxCons; index++) 834 { 835 if((This->connections[index].pAdvSink != NULL) && 836 (This->connections[index].advf & WINE_ADVF_REMOTE)) 837 { 838 IDataObject_DUnadvise(This->delegate, This->remote_connections[index]); 839 This->remote_connections[index] = 0; 840 This->connections[index].advf &= ~WINE_ADVF_REMOTE; 841 } 842 } 843 This->delegate = NULL; 844 } 845 846 /****************************************************************************** 847 * DataAdviseHolder_Constructor 848 */ 849 static IDataAdviseHolder *DataAdviseHolder_Constructor(void) 850 { 851 DataAdviseHolder* newHolder; 852 853 newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder)); 854 855 newHolder->IDataAdviseHolder_iface.lpVtbl = &DataAdviseHolderImpl_VTable; 856 newHolder->ref = 1; 857 newHolder->maxCons = INITIAL_SINKS; 858 newHolder->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 859 newHolder->maxCons * sizeof(*newHolder->connections)); 860 newHolder->remote_connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 861 newHolder->maxCons * sizeof(*newHolder->remote_connections)); 862 newHolder->delegate = NULL; 863 864 TRACE("returning %p\n", &newHolder->IDataAdviseHolder_iface); 865 return &newHolder->IDataAdviseHolder_iface; 866 } 867 868 /*********************************************************************** 869 * API functions 870 */ 871 872 /*********************************************************************** 873 * CreateOleAdviseHolder [OLE32.@] 874 */ 875 HRESULT WINAPI CreateOleAdviseHolder(IOleAdviseHolder **ppOAHolder) 876 { 877 TRACE("(%p)\n", ppOAHolder); 878 879 if (ppOAHolder==NULL) 880 return E_POINTER; 881 882 *ppOAHolder = OleAdviseHolderImpl_Constructor (); 883 884 if (*ppOAHolder != NULL) 885 return S_OK; 886 887 return E_OUTOFMEMORY; 888 } 889 890 /****************************************************************************** 891 * CreateDataAdviseHolder [OLE32.@] 892 */ 893 HRESULT WINAPI CreateDataAdviseHolder(IDataAdviseHolder **ppDAHolder) 894 { 895 TRACE("(%p)\n", ppDAHolder); 896 897 if (ppDAHolder==NULL) 898 return E_POINTER; 899 900 *ppDAHolder = DataAdviseHolder_Constructor(); 901 902 if (*ppDAHolder != NULL) 903 return S_OK; 904 905 return E_OUTOFMEMORY; 906 } 907