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