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