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