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