xref: /reactos/dll/win32/ole32/oleobj.c (revision 8c2e9189)
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