oleobj.c 25.2 KB
Newer Older
1 2 3 4
/*
 *	OLE2 COM objects
 *
 *	Copyright 1998 Eric Kohl
5
 *      Copyright 1999 Francis Beaudet
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 28
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
29

30
#include "windef.h"
31
#include "winbase.h"
32
#include "winuser.h"
33
#include "winerror.h"
34
#include "wine/debug.h"
35
#include "ole2.h"
36

37 38
#include "compobj_private.h"

39
WINE_DEFAULT_DEBUG_CHANNEL(ole);
40

41
#define INITIAL_SINKS 10
42

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
static void release_statdata(STATDATA *data)
{
    if(data->formatetc.ptd)
    {
        CoTaskMemFree(data->formatetc.ptd);
        data->formatetc.ptd = NULL;
    }

    if(data->pAdvSink)
    {
        IAdviseSink_Release(data->pAdvSink);
        data->pAdvSink = NULL;
    }
}

static HRESULT copy_statdata(STATDATA *dst, const STATDATA *src)
{
    *dst = *src;
    if(src->formatetc.ptd)
    {
        dst->formatetc.ptd = CoTaskMemAlloc(src->formatetc.ptd->tdSize);
        if(!dst->formatetc.ptd) return E_OUTOFMEMORY;
        memcpy(dst->formatetc.ptd, src->formatetc.ptd, src->formatetc.ptd->tdSize);
    }
    if(dst->pAdvSink) IAdviseSink_AddRef(dst->pAdvSink);
    return S_OK;
}

71
/**************************************************************************
72
 *  EnumSTATDATA Implementation
73
 */
74

75
static HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data, IEnumSTATDATA **ppenum);
76 77 78

typedef struct
{
79
    IEnumSTATDATA IEnumSTATDATA_iface;
80 81 82
    LONG ref;

    ULONG index;
83 84 85 86
    DWORD num_of_elems;
    STATDATA *statdata;
    IUnknown *holder;
} EnumSTATDATA;
87

88
static inline EnumSTATDATA *impl_from_IEnumSTATDATA(IEnumSTATDATA *iface)
89
{
90
    return CONTAINING_RECORD(iface, EnumSTATDATA, IEnumSTATDATA_iface);
91 92
}

93
static HRESULT WINAPI EnumSTATDATA_QueryInterface(IEnumSTATDATA *iface, REFIID riid, void **ppv)
94 95 96 97 98 99 100 101 102 103 104 105
{
    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
    if (IsEqualIID(riid, &IID_IUnknown) ||
        IsEqualIID(riid, &IID_IEnumSTATDATA))
    {
        IUnknown_AddRef(iface);
        *ppv = iface;
        return S_OK;
    }
    return E_NOINTERFACE;
}

106
static ULONG WINAPI EnumSTATDATA_AddRef(IEnumSTATDATA *iface)
107
{
108
    EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
109 110 111 112
    TRACE("()\n");
    return InterlockedIncrement(&This->ref);
}

113
static ULONG WINAPI EnumSTATDATA_Release(IEnumSTATDATA *iface)
114
{
115
    EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
116 117 118 119
    LONG refs = InterlockedDecrement(&This->ref);
    TRACE("()\n");
    if (!refs)
    {
120 121 122 123 124
        DWORD i;
        for(i = 0; i < This->num_of_elems; i++)
            release_statdata(This->statdata + i);
        HeapFree(GetProcessHeap(), 0, This->statdata);
        IUnknown_Release(This->holder);
125 126 127 128 129
        HeapFree(GetProcessHeap(), 0, This);
    }
    return refs;
}

130 131
static HRESULT WINAPI EnumSTATDATA_Next(IEnumSTATDATA *iface, ULONG num, LPSTATDATA data,
                                        ULONG *fetched)
132
{
133 134
    EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
    DWORD count = 0;
135 136
    HRESULT hr = S_OK;

137
    TRACE("(%d, %p, %p)\n", num, data, fetched);
138

139
    while(num--)
140
    {
141
        if (This->index >= This->num_of_elems)
142 143 144 145 146
        {
            hr = S_FALSE;
            break;
        }

147
        copy_statdata(data + count, This->statdata + This->index);
148

149
        count++;
150 151
        This->index++;
    }
152 153 154

    if (fetched) *fetched = count;

155 156 157
    return hr;
}

158
static HRESULT WINAPI EnumSTATDATA_Skip(IEnumSTATDATA *iface, ULONG num)
159
{
160
    EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
161

162
    TRACE("(%d)\n", num);
163

164
    if(This->index + num >= This->num_of_elems)
165
    {
166 167
        This->index = This->num_of_elems;
        return S_FALSE;
168
    }
169 170

    This->index += num;
171 172 173
    return S_OK;
}

174
static HRESULT WINAPI EnumSTATDATA_Reset(IEnumSTATDATA *iface)
175
{
176
    EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
177 178 179 180 181 182 183

    TRACE("()\n");

    This->index = 0;
    return S_OK;
}

184
static HRESULT WINAPI EnumSTATDATA_Clone(IEnumSTATDATA *iface, IEnumSTATDATA **ppenum)
185
{
186 187 188
    EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);

    return EnumSTATDATA_Construct(This->holder, This->index, This->num_of_elems, This->statdata, ppenum);
189 190
}

191
static const IEnumSTATDATAVtbl EnumSTATDATA_VTable =
192
{
193 194 195 196 197 198 199
    EnumSTATDATA_QueryInterface,
    EnumSTATDATA_AddRef,
    EnumSTATDATA_Release,
    EnumSTATDATA_Next,
    EnumSTATDATA_Skip,
    EnumSTATDATA_Reset,
    EnumSTATDATA_Clone
200 201
};

202
static HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data,
203
                                      IEnumSTATDATA **ppenum)
204
{
205
    EnumSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
206
    DWORD i, count;
207 208 209 210

    if (!This) return E_OUTOFMEMORY;

    This->IEnumSTATDATA_iface.lpVtbl = &EnumSTATDATA_VTable;
211 212
    This->ref = 1;
    This->index = index;
213

214
    This->statdata = HeapAlloc(GetProcessHeap(), 0, array_len * sizeof(*This->statdata));
215 216 217 218 219 220
    if(!This->statdata)
    {
        HeapFree(GetProcessHeap(), 0, This);
        return E_OUTOFMEMORY;
    }

221 222 223 224 225 226 227 228
    for(i = 0, count = 0; i < array_len; i++)
    {
        if(data[i].pAdvSink)
        {
            copy_statdata(This->statdata + count, data + i);
            count++;
        }
    }
229

230
    This->num_of_elems = count;
231 232
    This->holder = holder;
    IUnknown_AddRef(holder);
233 234
    *ppenum = &This->IEnumSTATDATA_iface;
    return S_OK;
235 236
}

237 238 239 240 241 242 243 244 245
/**************************************************************************
 *  OleAdviseHolder Implementation
 */
typedef struct
{
    IOleAdviseHolder IOleAdviseHolder_iface;

    LONG ref;

246 247
    DWORD max_cons;
    STATDATA *connections;
248 249 250 251 252 253 254
} OleAdviseHolderImpl;

static inline OleAdviseHolderImpl *impl_from_IOleAdviseHolder(IOleAdviseHolder *iface)
{
    return CONTAINING_RECORD(iface, OleAdviseHolderImpl, IOleAdviseHolder_iface);
}

255
/**************************************************************************
256
 *  OleAdviseHolderImpl_Destructor
257
 */
258
static void OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl *This)
259
{
260 261
    DWORD index;
    TRACE("%p\n", This);
262

263
    for (index = 0; index < This->max_cons; index++)
264
    {
265 266
        if (This->connections[index].pAdvSink != NULL)
            release_statdata(This->connections + index);
267
    }
268

269 270
    HeapFree(GetProcessHeap(), 0, This->connections);
    HeapFree(GetProcessHeap(), 0, This);
271
}
272

273 274 275
/**************************************************************************
 *  OleAdviseHolderImpl_QueryInterface
 */
276 277
static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(IOleAdviseHolder *iface,
                                                         REFIID iid, void **obj)
278
{
279 280
  OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
  TRACE("(%p)->(%s,%p)\n",This, debugstr_guid(iid), obj);
281

282
  if (obj == NULL)
283 284
    return E_POINTER;

285
  *obj = NULL;
286

287 288
  if (IsEqualIID(iid, &IID_IUnknown) ||
      IsEqualIID(iid, &IID_IOleAdviseHolder))
289
  {
290
    *obj = &This->IOleAdviseHolder_iface;
291 292
  }

293
  if(*obj == NULL)
294
    return E_NOINTERFACE;
295

296
  IUnknown_AddRef((IUnknown*)*obj);
297 298

  return S_OK;
299 300 301
}

/******************************************************************************
302
 * OleAdviseHolderImpl_AddRef
303
 */
304
static ULONG WINAPI OleAdviseHolderImpl_AddRef(IOleAdviseHolder *iface)
305
{
306
  OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
307 308
  ULONG ref = InterlockedIncrement(&This->ref);

309
  TRACE("(%p)->(ref=%d)\n", This, ref - 1);
310 311

  return ref;
312 313 314
}

/******************************************************************************
315
 * OleAdviseHolderImpl_Release
316
 */
317
static ULONG WINAPI OleAdviseHolderImpl_Release(IOleAdviseHolder *iface)
318
{
319
  OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
320
  ULONG ref;
321
  TRACE("(%p)->(ref=%d)\n", This, This->ref);
322
  ref = InterlockedDecrement(&This->ref);
323

324
  if (ref == 0) OleAdviseHolderImpl_Destructor(This);
325

326
  return ref;
327 328 329
}

/******************************************************************************
330
 * OleAdviseHolderImpl_Advise
331
 */
332 333 334
static HRESULT WINAPI OleAdviseHolderImpl_Advise(IOleAdviseHolder *iface,
                                                 IAdviseSink *pAdvise,
                                                 DWORD *pdwConnection)
335
{
336
  DWORD index;
337
  OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
338 339
  STATDATA new_conn;
  static const FORMATETC empty_fmtetc = {0, NULL, 0, -1, 0};
340

341
  TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection);
342 343 344

  if (pdwConnection==NULL)
    return E_POINTER;
345

346 347
  *pdwConnection = 0;

348
  for (index = 0; index < This->max_cons; index++)
349
  {
350
    if (This->connections[index].pAdvSink == NULL)
351 352 353
      break;
  }

354
  if (index == This->max_cons)
355
  {
356 357 358
    This->max_cons += INITIAL_SINKS;
    This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->connections,
                                    This->max_cons * sizeof(*This->connections));
359 360
  }

361 362 363 364
  new_conn.pAdvSink = pAdvise;
  new_conn.advf = 0;
  new_conn.formatetc = empty_fmtetc;
  new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */
365

366
  copy_statdata(This->connections + index, &new_conn);
367

368
  *pdwConnection = new_conn.dwConnection;
369 370

  return S_OK;
371 372 373
}

/******************************************************************************
374
 * OleAdviseHolderImpl_Unadvise
375
 */
376 377
static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(IOleAdviseHolder *iface,
                                                   DWORD dwConnection)
378
{
379
  OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
380
  DWORD index;
381

382
  TRACE("(%p)->(%u)\n", This, dwConnection);
383

384 385
  /* The connection number is 1 more than the index, see OleAdviseHolder_Advise */
  index = dwConnection - 1;
386

387 388
  if (index >= This->max_cons || This->connections[index].pAdvSink == NULL)
     return OLE_E_NOCONNECTION;
389

390
  release_statdata(This->connections + index);
391 392

  return S_OK;
393 394 395
}

/******************************************************************************
396
 * OleAdviseHolderImpl_EnumAdvise
397
 */
398
static HRESULT WINAPI OleAdviseHolderImpl_EnumAdvise(IOleAdviseHolder *iface, IEnumSTATDATA **enum_advise)
399
{
400
    OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
401 402
    IUnknown *unk;
    HRESULT hr;
403

404
    TRACE("(%p)->(%p)\n", This, enum_advise);
405 406

    IOleAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk);
407
    hr = EnumSTATDATA_Construct(unk, 0, This->max_cons, This->connections, enum_advise);
408 409
    IUnknown_Release(unk);
    return hr;
410 411 412
}

/******************************************************************************
413
 * OleAdviseHolderImpl_SendOnRename
414
 */
415
static HRESULT WINAPI OleAdviseHolderImpl_SendOnRename(IOleAdviseHolder *iface, IMoniker *pmk)
416
{
417 418
    IEnumSTATDATA *pEnum;
    HRESULT hr;
419

420
    TRACE("(%p)->(%p)\n", iface, pmk);
421

422 423 424 425 426 427 428 429 430 431 432 433 434 435
    hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
    if (SUCCEEDED(hr))
    {
        STATDATA statdata;
        while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
        {
            IAdviseSink_OnRename(statdata.pAdvSink, pmk);

            IAdviseSink_Release(statdata.pAdvSink);
        }
        IEnumSTATDATA_Release(pEnum);
    }

    return hr;
436 437 438
}

/******************************************************************************
439
 * OleAdviseHolderImpl_SendOnSave
440
 */
441
static HRESULT WINAPI OleAdviseHolderImpl_SendOnSave(IOleAdviseHolder *iface)
442
{
443 444
    IEnumSTATDATA *pEnum;
    HRESULT hr;
445

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    TRACE("(%p)->()\n", iface);

    hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
    if (SUCCEEDED(hr))
    {
        STATDATA statdata;
        while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
        {
            IAdviseSink_OnSave(statdata.pAdvSink);

            IAdviseSink_Release(statdata.pAdvSink);
        }
        IEnumSTATDATA_Release(pEnum);
    }

    return hr;
462 463 464
}

/******************************************************************************
465
 * OleAdviseHolderImpl_SendOnClose
466
 */
467
static HRESULT WINAPI OleAdviseHolderImpl_SendOnClose(IOleAdviseHolder *iface)
468
{
469 470
    IEnumSTATDATA *pEnum;
    HRESULT hr;
471

472
    TRACE("(%p)->()\n", iface);
473

474 475 476 477 478 479 480 481 482 483 484 485 486 487
    hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
    if (SUCCEEDED(hr))
    {
        STATDATA statdata;
        while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
        {
            IAdviseSink_OnClose(statdata.pAdvSink);

            IAdviseSink_Release(statdata.pAdvSink);
        }
        IEnumSTATDATA_Release(pEnum);
    }

    return hr;
488 489
}

490 491 492
/**************************************************************************
 *  OleAdviseHolderImpl_VTable
 */
493
static const IOleAdviseHolderVtbl oahvt =
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
{
    OleAdviseHolderImpl_QueryInterface,
    OleAdviseHolderImpl_AddRef,
    OleAdviseHolderImpl_Release,
    OleAdviseHolderImpl_Advise,
    OleAdviseHolderImpl_Unadvise,
    OleAdviseHolderImpl_EnumAdvise,
    OleAdviseHolderImpl_SendOnRename,
    OleAdviseHolderImpl_SendOnSave,
    OleAdviseHolderImpl_SendOnClose
};

/**************************************************************************
 *  OleAdviseHolderImpl_Constructor
 */

510
static IOleAdviseHolder *OleAdviseHolderImpl_Constructor(void)
511 512 513 514 515
{
  OleAdviseHolderImpl* lpoah;

  lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl));

516
  lpoah->IOleAdviseHolder_iface.lpVtbl = &oahvt;
517
  lpoah->ref = 1;
518 519 520
  lpoah->max_cons = INITIAL_SINKS;
  lpoah->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                 lpoah->max_cons * sizeof(*lpoah->connections));
521

522 523
  TRACE("returning %p\n",  &lpoah->IOleAdviseHolder_iface);
  return &lpoah->IOleAdviseHolder_iface;
524 525
}

526 527 528
/**************************************************************************
 *  DataAdviseHolder Implementation
 */
529
typedef struct
530
{
531
  IDataAdviseHolder     IDataAdviseHolder_iface;
532

533
  LONG                  ref;
534
  DWORD                 maxCons;
535 536
  STATDATA*             connections;
  DWORD*                remote_connections;
537
  IDataObject*          delegate;
538 539
} DataAdviseHolder;

540 541 542
/* this connection has also has been advised to the delegate data object */
#define WINE_ADVF_REMOTE 0x80000000

543 544 545 546 547
static inline DataAdviseHolder *impl_from_IDataAdviseHolder(IDataAdviseHolder *iface)
{
    return CONTAINING_RECORD(iface, DataAdviseHolder, IDataAdviseHolder_iface);
}

548 549 550
/******************************************************************************
 * DataAdviseHolder_Destructor
 */
551
static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
552
{
553 554 555 556 557
  DWORD index;
  TRACE("%p\n", ptrToDestroy);

  for (index = 0; index < ptrToDestroy->maxCons; index++)
  {
558
    if (ptrToDestroy->connections[index].pAdvSink != NULL)
559
    {
560
      if (ptrToDestroy->delegate && 
561
          (ptrToDestroy->connections[index].advf & WINE_ADVF_REMOTE))
562
        IDataObject_DUnadvise(ptrToDestroy->delegate,
563
          ptrToDestroy->remote_connections[index]);
564

565
      release_statdata(ptrToDestroy->connections + index);
566 567
    }
  }
568

569 570
  HeapFree(GetProcessHeap(), 0, ptrToDestroy->remote_connections);
  HeapFree(GetProcessHeap(), 0, ptrToDestroy->connections);
571
  HeapFree(GetProcessHeap(), 0, ptrToDestroy);
572 573 574 575 576
}

/************************************************************************
 * DataAdviseHolder_QueryInterface (IUnknown)
 */
577 578
static HRESULT WINAPI DataAdviseHolder_QueryInterface(IDataAdviseHolder *iface,
                                                      REFIID riid, void **ppvObject)
579
{
580
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
581
  TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
582

583 584
  if ( (This==0) || (ppvObject==0) )
    return E_INVALIDARG;
585

586 587
  *ppvObject = 0;

588 589
  if ( IsEqualIID(&IID_IUnknown, riid) ||
       IsEqualIID(&IID_IDataAdviseHolder, riid)  )
590 591 592
  {
    *ppvObject = iface;
  }
593

594 595 596 597
  if ((*ppvObject)==0)
  {
    return E_NOINTERFACE;
  }
598

599
  IUnknown_AddRef((IUnknown*)*ppvObject);
600
  return S_OK;
601 602 603 604 605
}

/************************************************************************
 * DataAdviseHolder_AddRef (IUnknown)
 */
606
static ULONG WINAPI DataAdviseHolder_AddRef(IDataAdviseHolder *iface)
607
{
608
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
609
  TRACE("(%p) (ref=%d)\n", This, This->ref);
610
  return InterlockedIncrement(&This->ref);
611 612 613 614 615
}

/************************************************************************
 * DataAdviseHolder_Release (IUnknown)
 */
616
static ULONG WINAPI DataAdviseHolder_Release(IDataAdviseHolder *iface)
617
{
618
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
619
  ULONG ref;
620
  TRACE("(%p) (ref=%d)\n", This, This->ref);
621

622 623
  ref = InterlockedDecrement(&This->ref);
  if (ref==0) DataAdviseHolder_Destructor(This);
624

625
  return ref;
626 627
}

628 629 630 631
/************************************************************************
 * DataAdviseHolder_Advise
 *
 */
632 633 634 635
static HRESULT WINAPI DataAdviseHolder_Advise(IDataAdviseHolder *iface,
                                              IDataObject *pDataObject, FORMATETC *pFetc,
                                              DWORD advf, IAdviseSink *pAdvise,
                                              DWORD *pdwConnection)
636
{
637
  DWORD index;
638
  STATDATA new_conn;
639
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
640

641
  TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf,
642
	pAdvise, pdwConnection);
643

644 645
  if (pdwConnection==NULL)
    return E_POINTER;
646

647 648 649 650
  *pdwConnection = 0;

  for (index = 0; index < This->maxCons; index++)
  {
651
    if (This->connections[index].pAdvSink == NULL)
652 653 654 655 656 657
      break;
  }

  if (index == This->maxCons)
  {
    This->maxCons+=INITIAL_SINKS;
658 659 660 661 662 663
    This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                    This->connections,
                                    This->maxCons * sizeof(*This->connections));
    This->remote_connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                           This->remote_connections,
                                           This->maxCons * sizeof(*This->remote_connections));
664
  }
665

666 667 668 669
  new_conn.pAdvSink = pAdvise;
  new_conn.advf = advf & ~WINE_ADVF_REMOTE;
  new_conn.formatetc = *pFetc;
  new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */
670

671
  copy_statdata(This->connections + index, &new_conn);
672

673 674
  if (This->connections[index].pAdvSink != NULL)
  {
675 676 677 678 679
    /* if we are already connected advise the remote object */
    if (This->delegate)
    {
        HRESULT hr;

680 681 682
        hr = IDataObject_DAdvise(This->delegate, &new_conn.formatetc,
                                 new_conn.advf, new_conn.pAdvSink,
                                 &This->remote_connections[index]);
683 684
        if (FAILED(hr))
        {
685
            IDataAdviseHolder_Unadvise(iface, new_conn.dwConnection);
686 687
            return hr;
        }
688
        This->connections[index].advf |= WINE_ADVF_REMOTE;
689
    }
690 691 692 693
    else if(advf & ADVF_PRIMEFIRST)
      /* only do this if we have no delegate, since in the above case the
       * delegate will do the priming for us */
      IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
694
  }
695 696

  *pdwConnection = new_conn.dwConnection;
697 698

  return S_OK;
699 700
}

701 702 703
/******************************************************************************
 * DataAdviseHolder_Unadvise
 */
704 705
static HRESULT WINAPI DataAdviseHolder_Unadvise(IDataAdviseHolder *iface,
                                                DWORD dwConnection)
706
{
707
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
708
  DWORD index;
709
  TRACE("(%p)->(%u)\n", This, dwConnection);
710

711 712
  /* The connection number is 1 more than the index, see DataAdviseHolder_Advise */
  index = dwConnection - 1;
713

714 715
  if (index >= This->maxCons || This->connections[index].pAdvSink == NULL)
     return OLE_E_NOCONNECTION;
716

717 718 719 720 721
  if (This->delegate && This->connections[index].advf & WINE_ADVF_REMOTE)
  {
    IDataObject_DUnadvise(This->delegate, This->remote_connections[index]);
    This->remote_connections[index] = 0;
  }
722

723
  release_statdata(This->connections + index);
724

725
  return S_OK;
726 727
}

728 729 730 731 732
/******************************************************************************
 * DataAdviseHolder_EnumAdvise
 */
static HRESULT WINAPI DataAdviseHolder_EnumAdvise(IDataAdviseHolder *iface,
                                                  IEnumSTATDATA **enum_advise)
733
{
734
    DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
735 736 737 738
    IUnknown *unk;
    HRESULT hr;

    TRACE("(%p)->(%p)\n", This, enum_advise);
739

740 741 742 743
    IDataAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk);
    hr = EnumSTATDATA_Construct(unk, 0, This->maxCons, This->connections, enum_advise);
    IUnknown_Release(unk);
    return hr;
744 745
}

746 747 748
/******************************************************************************
 * DataAdviseHolder_SendOnDataChange
 */
749
static HRESULT WINAPI DataAdviseHolder_SendOnDataChange(IDataAdviseHolder *iface,
750
                                                        IDataObject *data_obj,
751
                                                        DWORD dwReserved, DWORD advf)
752
{
753 754
    IEnumSTATDATA *pEnum;
    HRESULT hr;
755

756
    TRACE("(%p)->(%p, %08x, %08x)\n", iface, data_obj, dwReserved, advf);
757

758 759
    hr = IDataAdviseHolder_EnumAdvise(iface, &pEnum);
    if (SUCCEEDED(hr))
760
    {
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
        STATDATA statdata;
        while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
        {
            STGMEDIUM stg;
            stg.tymed = TYMED_NULL;
            stg.u.pstg = NULL;
            stg.pUnkForRelease = NULL;

            if(!(statdata.advf & ADVF_NODATA))
            {
                hr = IDataObject_GetData(data_obj, &statdata.formatetc, &stg);
            }

            IAdviseSink_OnDataChange(statdata.pAdvSink, &statdata.formatetc, &stg);

            if(statdata.advf & ADVF_ONLYONCE)
            {
                IDataAdviseHolder_Unadvise(iface, statdata.dwConnection);
            }

            release_statdata(&statdata);
        }
        IEnumSTATDATA_Release(pEnum);
784
    }
785 786

    return S_OK;
787 788
}

789 790 791
/**************************************************************************
 *  DataAdviseHolderImpl_VTable
 */
792
static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
793 794 795 796 797 798 799 800 801 802
{
  DataAdviseHolder_QueryInterface,
  DataAdviseHolder_AddRef,
  DataAdviseHolder_Release,
  DataAdviseHolder_Advise,
  DataAdviseHolder_Unadvise,
  DataAdviseHolder_EnumAdvise,
  DataAdviseHolder_SendOnDataChange
};

803 804
HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate)
{
805
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
806 807 808 809 810
  DWORD index;
  HRESULT hr = S_OK;

  for(index = 0; index < This->maxCons; index++)
  {
811
    if(This->connections[index].pAdvSink != NULL)
812
    {
813 814 815 816
      hr = IDataObject_DAdvise(pDelegate, &This->connections[index].formatetc,
                               This->connections[index].advf,
                               This->connections[index].pAdvSink,
                               &This->remote_connections[index]);
817
      if (FAILED(hr)) break;
818
      This->connections[index].advf |= WINE_ADVF_REMOTE;
819 820
    }
  }
821
  This->delegate = pDelegate;
822 823 824 825 826
  return hr;
}

void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface)
{
827
  DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
828 829 830 831
  DWORD index;

  for(index = 0; index < This->maxCons; index++)
  {
832 833
    if((This->connections[index].pAdvSink != NULL) &&
       (This->connections[index].advf & WINE_ADVF_REMOTE))
834
    {
835 836 837
      IDataObject_DUnadvise(This->delegate, This->remote_connections[index]);
      This->remote_connections[index] = 0;
      This->connections[index].advf &= ~WINE_ADVF_REMOTE;
838 839 840
    }
  }
  This->delegate = NULL;
841 842
}

843 844 845
/******************************************************************************
 * DataAdviseHolder_Constructor
 */
846
static IDataAdviseHolder *DataAdviseHolder_Constructor(void)
847 848 849 850 851
{
  DataAdviseHolder* newHolder;

  newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder));

852
  newHolder->IDataAdviseHolder_iface.lpVtbl = &DataAdviseHolderImpl_VTable;
853 854
  newHolder->ref = 1;
  newHolder->maxCons = INITIAL_SINKS;
855 856 857 858
  newHolder->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                     newHolder->maxCons * sizeof(*newHolder->connections));
  newHolder->remote_connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                            newHolder->maxCons * sizeof(*newHolder->remote_connections));
859
  newHolder->delegate = NULL;
860

861 862
  TRACE("returning %p\n", &newHolder->IDataAdviseHolder_iface);
  return &newHolder->IDataAdviseHolder_iface;
863 864
}

865 866 867 868 869
/***********************************************************************
 * API functions
 */

/***********************************************************************
870
 * CreateOleAdviseHolder [OLE32.@]
871
 */
872
HRESULT WINAPI CreateOleAdviseHolder(IOleAdviseHolder **ppOAHolder)
873
{
874
  TRACE("(%p)\n", ppOAHolder);
875 876 877 878 879 880 881 882 883 884 885 886 887

  if (ppOAHolder==NULL)
    return E_POINTER;

  *ppOAHolder = OleAdviseHolderImpl_Constructor ();

  if (*ppOAHolder != NULL)
    return S_OK;

  return E_OUTOFMEMORY;
}

/******************************************************************************
888
 *              CreateDataAdviseHolder        [OLE32.@]
889
 */
890
HRESULT WINAPI CreateDataAdviseHolder(IDataAdviseHolder **ppDAHolder)
891
{
892
  TRACE("(%p)\n", ppDAHolder);
893

894 895 896 897 898 899 900
  if (ppDAHolder==NULL)
    return E_POINTER;

  *ppDAHolder = DataAdviseHolder_Constructor();

  if (*ppDAHolder != NULL)
    return S_OK;
901

902
  return E_OUTOFMEMORY;
903
}