- Implement CoDisconnectObject.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36
37 #define INITIAL_SINKS 10
38
39 /**************************************************************************
40  *  OleAdviseHolderImpl Implementation
41  */
42 typedef struct OleAdviseHolderImpl
43 {
44   IOleAdviseHolderVtbl *lpVtbl;
45
46   DWORD ref;
47
48   DWORD         maxSinks;
49   IAdviseSink** arrayOfSinks;
50
51 } OleAdviseHolderImpl;
52
53 static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor(void);
54 static void              OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl* ptrToDestroy);
55 static HRESULT WINAPI    OleAdviseHolderImpl_QueryInterface(LPOLEADVISEHOLDER,REFIID,LPVOID*);
56 static ULONG WINAPI      OleAdviseHolderImpl_AddRef(LPOLEADVISEHOLDER);
57 static ULONG WINAPI      OleAdviseHolderImpl_Release(LPOLEADVISEHOLDER);
58 static HRESULT WINAPI    OleAdviseHolderImpl_Advise(LPOLEADVISEHOLDER, IAdviseSink*, DWORD*);
59 static HRESULT WINAPI    OleAdviseHolderImpl_Unadvise (LPOLEADVISEHOLDER, DWORD);
60 static HRESULT WINAPI    OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER, IEnumSTATDATA **);
61 static HRESULT WINAPI    OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER, IMoniker *);
62 static HRESULT WINAPI    OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER);
63 static HRESULT WINAPI    OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER);
64
65
66 /**************************************************************************
67  *  OleAdviseHolderImpl_VTable
68  */
69 static struct IOleAdviseHolderVtbl oahvt =
70 {
71     OleAdviseHolderImpl_QueryInterface,
72     OleAdviseHolderImpl_AddRef,
73     OleAdviseHolderImpl_Release,
74     OleAdviseHolderImpl_Advise,
75     OleAdviseHolderImpl_Unadvise,
76     OleAdviseHolderImpl_EnumAdvise,
77     OleAdviseHolderImpl_SendOnRename,
78     OleAdviseHolderImpl_SendOnSave,
79     OleAdviseHolderImpl_SendOnClose
80 };
81
82 /**************************************************************************
83  *  OleAdviseHolderImpl_Constructor
84  */
85
86 static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor()
87 {
88   OleAdviseHolderImpl* lpoah;
89   DWORD                index;
90
91   lpoah= (OleAdviseHolderImpl*)HeapAlloc(GetProcessHeap(),
92                                          0,
93                                          sizeof(OleAdviseHolderImpl));
94
95   lpoah->lpVtbl = &oahvt;
96   lpoah->ref = 1;
97   lpoah->maxSinks = INITIAL_SINKS;
98   lpoah->arrayOfSinks = HeapAlloc(GetProcessHeap(),
99                                   0,
100                                   lpoah->maxSinks * sizeof(IAdviseSink*));
101
102   for (index = 0; index < lpoah->maxSinks; index++)
103     lpoah->arrayOfSinks[index]=0;
104
105   TRACE("returning %p\n", lpoah);
106   return (LPOLEADVISEHOLDER)lpoah;
107 }
108
109 /**************************************************************************
110  *  OleAdviseHolderImpl_Destructor
111  */
112 static void OleAdviseHolderImpl_Destructor(
113   OleAdviseHolderImpl* ptrToDestroy)
114 {
115   DWORD index;
116   TRACE("%p\n", ptrToDestroy);
117
118   for (index = 0; index < ptrToDestroy->maxSinks; index++)
119   {
120     if (ptrToDestroy->arrayOfSinks[index]!=0)
121     {
122       IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]);
123       ptrToDestroy->arrayOfSinks[index] = NULL;
124     }
125   }
126
127   HeapFree(GetProcessHeap(),
128            0,
129            ptrToDestroy->arrayOfSinks);
130
131
132   HeapFree(GetProcessHeap(),
133            0,
134            ptrToDestroy);
135 }
136
137 /**************************************************************************
138  *  OleAdviseHolderImpl_QueryInterface
139  */
140 static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(
141   LPOLEADVISEHOLDER iface,
142   REFIID            riid,
143   LPVOID*           ppvObj)
144 {
145   OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
146   TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObj);
147   /*
148    * Sanity check
149    */
150   if (ppvObj==NULL)
151     return E_POINTER;
152
153   *ppvObj = NULL;
154
155   if (IsEqualIID(riid, &IID_IUnknown))
156   {
157     /* IUnknown */
158     *ppvObj = This;
159   }
160   else if(IsEqualIID(riid, &IID_IOleAdviseHolder))
161   {
162     /* IOleAdviseHolder */
163     *ppvObj = (IOleAdviseHolder*) This;
164   }
165
166   if(*ppvObj == NULL)
167     return E_NOINTERFACE;
168
169   /*
170    * A successful QI always increments the reference count.
171    */
172   IUnknown_AddRef((IUnknown*)*ppvObj);
173
174   return S_OK;
175 }
176
177 /******************************************************************************
178  * OleAdviseHolderImpl_AddRef
179  */
180 static ULONG WINAPI OleAdviseHolderImpl_AddRef(
181   LPOLEADVISEHOLDER iface)
182 {
183   OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
184   ULONG ref = InterlockedIncrement(&This->ref);
185
186   TRACE("(%p)->(ref=%ld)\n", This, ref - 1);
187
188   return ref;
189 }
190
191 /******************************************************************************
192  * OleAdviseHolderImpl_Release
193  */
194 static ULONG WINAPI OleAdviseHolderImpl_Release(
195   LPOLEADVISEHOLDER iface)
196 {
197   OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
198   ULONG ref;
199   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
200   ref = InterlockedDecrement(&This->ref);
201
202   if (ref == 0) OleAdviseHolderImpl_Destructor(This);
203
204   return ref;
205 }
206
207 /******************************************************************************
208  * OleAdviseHolderImpl_Advise
209  */
210 static HRESULT WINAPI OleAdviseHolderImpl_Advise(
211   LPOLEADVISEHOLDER iface,
212   IAdviseSink*      pAdvise,
213   DWORD*            pdwConnection)
214 {
215   DWORD index;
216
217   OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
218
219   TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection);
220
221   /*
222    * Sanity check
223    */
224   if (pdwConnection==NULL)
225     return E_POINTER;
226
227   *pdwConnection = 0;
228
229   /*
230    * Find a free spot in the array.
231    */
232   for (index = 0; index < This->maxSinks; index++)
233   {
234     if (This->arrayOfSinks[index]==NULL)
235       break;
236   }
237
238   /*
239    * If the array is full, we need to grow it.
240    */
241   if (index == This->maxSinks)
242   {
243     DWORD i;
244
245     This->maxSinks+=INITIAL_SINKS;
246
247     This->arrayOfSinks = HeapReAlloc(GetProcessHeap(),
248                                      0,
249                                      This->arrayOfSinks,
250                                      This->maxSinks*sizeof(IAdviseSink*));
251
252     for (i=index;i < This->maxSinks; i++)
253       This->arrayOfSinks[i]=0;
254   }
255
256   /*
257    * Store the new sink
258    */
259   This->arrayOfSinks[index] = pAdvise;
260
261   if (This->arrayOfSinks[index]!=NULL)
262     IAdviseSink_AddRef(This->arrayOfSinks[index]);
263
264   /*
265    * Return the index as the cookie.
266    * Since 0 is not a valid cookie, we will increment by
267    * 1 the index in the table.
268    */
269   *pdwConnection = index+1;
270
271   return S_OK;
272 }
273
274 /******************************************************************************
275  * OleAdviseHolderImpl_Unadvise
276  */
277 static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(
278   LPOLEADVISEHOLDER iface,
279   DWORD             dwConnection)
280 {
281   OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
282
283   TRACE("(%p)->(%lu)\n", This, dwConnection);
284
285   /*
286    * So we don't return 0 as a cookie, the index was
287    * incremented by 1 in OleAdviseHolderImpl_Advise
288    * we have to compensate.
289    */
290   dwConnection--;
291
292   /*
293    * Check for invalid cookies.
294    */
295   if (dwConnection >= This->maxSinks)
296     return OLE_E_NOCONNECTION;
297
298   if (This->arrayOfSinks[dwConnection] == NULL)
299     return OLE_E_NOCONNECTION;
300
301   /*
302    * Release the sink and mark the spot in the list as free.
303    */
304   IAdviseSink_Release(This->arrayOfSinks[dwConnection]);
305   This->arrayOfSinks[dwConnection] = NULL;
306
307   return S_OK;
308 }
309
310 /******************************************************************************
311  * OleAdviseHolderImpl_EnumAdvise
312  */
313 static HRESULT WINAPI
314 OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise)
315 {
316     OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
317     FIXME("(%p)->(%p)\n", This, ppenumAdvise);
318
319     *ppenumAdvise = NULL;
320
321     return S_OK;
322 }
323
324 /******************************************************************************
325  * OleAdviseHolderImpl_SendOnRename
326  */
327 static HRESULT WINAPI
328 OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk)
329 {
330     OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
331     FIXME("(%p)->(%p)\n", This, pmk);
332
333
334     return S_OK;
335 }
336
337 /******************************************************************************
338  * OleAdviseHolderImpl_SendOnSave
339  */
340 static HRESULT WINAPI
341 OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface)
342 {
343     OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
344     FIXME("(%p)\n", This);
345
346     return S_OK;
347 }
348
349 /******************************************************************************
350  * OleAdviseHolderImpl_SendOnClose
351  */
352 static HRESULT WINAPI
353 OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface)
354 {
355     OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
356     FIXME("(%p)\n", This);
357
358
359     return S_OK;
360 }
361
362 /**************************************************************************
363  *  DataAdviseHolder Implementation
364  */
365 typedef struct DataAdviseConnection {
366   IAdviseSink *sink;
367   FORMATETC fmat;
368   DWORD advf;
369 } DataAdviseConnection;
370
371 typedef struct DataAdviseHolder
372 {
373   IDataAdviseHolderVtbl *lpVtbl;
374
375   DWORD                 ref;
376   DWORD                 maxCons;
377   DataAdviseConnection* Connections;
378 } DataAdviseHolder;
379
380 /**************************************************************************
381  *  DataAdviseHolder method prototypes
382  */
383 static IDataAdviseHolder* DataAdviseHolder_Constructor(void);
384 static void               DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy);
385 static HRESULT WINAPI     DataAdviseHolder_QueryInterface(
386                             IDataAdviseHolder*      iface,
387                             REFIID                  riid,
388                             void**                  ppvObject);
389 static ULONG WINAPI       DataAdviseHolder_AddRef(
390                             IDataAdviseHolder*      iface);
391 static ULONG WINAPI       DataAdviseHolder_Release(
392                             IDataAdviseHolder*      iface);
393 static HRESULT WINAPI     DataAdviseHolder_Advise(
394                             IDataAdviseHolder*      iface,
395                             IDataObject*            pDataObject,
396                             FORMATETC*              pFetc,
397                             DWORD                   advf,
398                             IAdviseSink*            pAdvise,
399                             DWORD*                  pdwConnection);
400 static HRESULT WINAPI     DataAdviseHolder_Unadvise(
401                             IDataAdviseHolder*      iface,
402                             DWORD                   dwConnection);
403 static HRESULT WINAPI     DataAdviseHolder_EnumAdvise(
404                             IDataAdviseHolder*      iface,
405                             IEnumSTATDATA**         ppenumAdvise);
406 static HRESULT WINAPI     DataAdviseHolder_SendOnDataChange(
407                             IDataAdviseHolder*      iface,
408                             IDataObject*            pDataObject,
409                             DWORD                   dwReserved,
410                             DWORD                   advf);
411
412 /**************************************************************************
413  *  DataAdviseHolderImpl_VTable
414  */
415 static struct IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
416 {
417   DataAdviseHolder_QueryInterface,
418   DataAdviseHolder_AddRef,
419   DataAdviseHolder_Release,
420   DataAdviseHolder_Advise,
421   DataAdviseHolder_Unadvise,
422   DataAdviseHolder_EnumAdvise,
423   DataAdviseHolder_SendOnDataChange
424 };
425
426 /******************************************************************************
427  * DataAdviseHolder_Constructor
428  */
429 static IDataAdviseHolder* DataAdviseHolder_Constructor()
430 {
431   DataAdviseHolder* newHolder;
432
433   newHolder = (DataAdviseHolder*)HeapAlloc(GetProcessHeap(),
434                                            0,
435                                            sizeof(DataAdviseHolder));
436
437   newHolder->lpVtbl = &DataAdviseHolderImpl_VTable;
438   newHolder->ref = 1;
439   newHolder->maxCons = INITIAL_SINKS;
440   newHolder->Connections = HeapAlloc(GetProcessHeap(),
441                                      HEAP_ZERO_MEMORY,
442                                      newHolder->maxCons *
443                                      sizeof(DataAdviseConnection));
444
445   TRACE("returning %p\n", newHolder);
446   return (IDataAdviseHolder*)newHolder;
447 }
448
449 /******************************************************************************
450  * DataAdviseHolder_Destructor
451  */
452 static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
453 {
454   DWORD index;
455   TRACE("%p\n", ptrToDestroy);
456
457   for (index = 0; index < ptrToDestroy->maxCons; index++)
458   {
459     if (ptrToDestroy->Connections[index].sink != NULL)
460     {
461       IAdviseSink_Release(ptrToDestroy->Connections[index].sink);
462       ptrToDestroy->Connections[index].sink = NULL;
463     }
464   }
465
466   HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections);
467   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
468 }
469
470 /************************************************************************
471  * DataAdviseHolder_QueryInterface (IUnknown)
472  *
473  * See Windows documentation for more details on IUnknown methods.
474  */
475 static HRESULT WINAPI DataAdviseHolder_QueryInterface(
476   IDataAdviseHolder*      iface,
477   REFIID                  riid,
478   void**                  ppvObject)
479 {
480   DataAdviseHolder *This = (DataAdviseHolder *)iface;
481   TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
482   /*
483    * Perform a sanity check on the parameters.
484    */
485   if ( (This==0) || (ppvObject==0) )
486     return E_INVALIDARG;
487
488   /*
489    * Initialize the return parameter.
490    */
491   *ppvObject = 0;
492
493   /*
494    * Compare the riid with the interface IDs implemented by this object.
495    */
496   if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) ||
497        (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0)  )
498   {
499     *ppvObject = iface;
500   }
501
502   /*
503    * Check that we obtained an interface.
504    */
505   if ((*ppvObject)==0)
506   {
507     return E_NOINTERFACE;
508   }
509
510   /*
511    * Query Interface always increases the reference count by one when it is
512    * successful.
513    */
514   IUnknown_AddRef((IUnknown*)*ppvObject);
515
516   return S_OK;
517 }
518
519 /************************************************************************
520  * DataAdviseHolder_AddRef (IUnknown)
521  *
522  * See Windows documentation for more details on IUnknown methods.
523  */
524 static ULONG WINAPI       DataAdviseHolder_AddRef(
525   IDataAdviseHolder*      iface)
526 {
527   DataAdviseHolder *This = (DataAdviseHolder *)iface;
528   TRACE("(%p) (ref=%ld)\n", This, This->ref);
529   return InterlockedIncrement(&This->ref);
530 }
531
532 /************************************************************************
533  * DataAdviseHolder_Release (IUnknown)
534  *
535  * See Windows documentation for more details on IUnknown methods.
536  */
537 static ULONG WINAPI DataAdviseHolder_Release(
538   IDataAdviseHolder*      iface)
539 {
540   DataAdviseHolder *This = (DataAdviseHolder *)iface;
541   ULONG ref;
542   TRACE("(%p) (ref=%ld)\n", This, This->ref);
543
544   /*
545    * Decrease the reference count on this object.
546    */
547   ref = InterlockedDecrement(&This->ref);
548
549   /*
550    * If the reference count goes down to 0, perform suicide.
551    */
552   if (ref==0) DataAdviseHolder_Destructor(This);
553
554   return ref;
555 }
556
557 /************************************************************************
558  * DataAdviseHolder_Advise
559  *
560  */
561 static HRESULT WINAPI DataAdviseHolder_Advise(
562   IDataAdviseHolder*      iface,
563   IDataObject*            pDataObject,
564   FORMATETC*              pFetc,
565   DWORD                   advf,
566   IAdviseSink*            pAdvise,
567   DWORD*                  pdwConnection)
568 {
569   DWORD index;
570
571   DataAdviseHolder *This = (DataAdviseHolder *)iface;
572
573   TRACE("(%p)->(%p, %p, %08lx, %p, %p)\n", This, pDataObject, pFetc, advf,
574         pAdvise, pdwConnection);
575   /*
576    * Sanity check
577    */
578   if (pdwConnection==NULL)
579     return E_POINTER;
580
581   *pdwConnection = 0;
582
583   /*
584    * Find a free spot in the array.
585    */
586   for (index = 0; index < This->maxCons; index++)
587   {
588     if (This->Connections[index].sink == NULL)
589       break;
590   }
591
592   /*
593    * If the array is full, we need to grow it.
594    */
595   if (index == This->maxCons)
596   {
597     This->maxCons+=INITIAL_SINKS;
598     This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
599                                     This->Connections,
600                                     This->maxCons*sizeof(DataAdviseConnection));
601   }
602   /*
603    * Store the new sink
604    */
605   This->Connections[index].sink = pAdvise;
606   memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC));
607   This->Connections[index].advf = advf;
608
609   if (This->Connections[index].sink != NULL) {
610     IAdviseSink_AddRef(This->Connections[index].sink);
611     if(advf & ADVF_PRIMEFIRST) {
612       DataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
613     }
614   }
615   /*
616    * Return the index as the cookie.
617    * Since 0 is not a valid cookie, we will increment by
618    * 1 the index in the table.
619    */
620   *pdwConnection = index+1;
621
622   return S_OK;
623 }
624
625 /******************************************************************************
626  * DataAdviseHolder_Unadvise
627  */
628 static HRESULT WINAPI     DataAdviseHolder_Unadvise(
629   IDataAdviseHolder*      iface,
630   DWORD                   dwConnection)
631 {
632   DataAdviseHolder *This = (DataAdviseHolder *)iface;
633
634   TRACE("(%p)->(%lu)\n", This, dwConnection);
635
636   /*
637    * So we don't return 0 as a cookie, the index was
638    * incremented by 1 in OleAdviseHolderImpl_Advise
639    * we have to compensate.
640    */
641   dwConnection--;
642
643   /*
644    * Check for invalid cookies.
645    */
646   if (dwConnection >= This->maxCons)
647     return OLE_E_NOCONNECTION;
648
649   if (This->Connections[dwConnection].sink == NULL)
650     return OLE_E_NOCONNECTION;
651
652   /*
653    * Release the sink and mark the spot in the list as free.
654    */
655   IAdviseSink_Release(This->Connections[dwConnection].sink);
656   memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection));
657   return S_OK;
658 }
659
660 static HRESULT WINAPI     DataAdviseHolder_EnumAdvise(
661   IDataAdviseHolder*      iface,
662   IEnumSTATDATA**         ppenumAdvise)
663 {
664   DataAdviseHolder *This = (DataAdviseHolder *)iface;
665
666   FIXME("(%p)->(%p)\n", This, ppenumAdvise);
667   return E_NOTIMPL;
668 }
669
670 /******************************************************************************
671  * DataAdviseHolder_SendOnDataChange
672  */
673 static HRESULT WINAPI     DataAdviseHolder_SendOnDataChange(
674   IDataAdviseHolder*      iface,
675   IDataObject*            pDataObject,
676   DWORD                   dwReserved,
677   DWORD                   advf)
678 {
679   DataAdviseHolder *This = (DataAdviseHolder *)iface;
680   DWORD index;
681   STGMEDIUM stg;
682   HRESULT res;
683
684   TRACE("(%p)->(%p,%08lx,%08lx)\n", This, pDataObject, dwReserved, advf);
685
686   for(index = 0; index < This->maxCons; index++) {
687     if(This->Connections[index].sink != NULL) {
688       if(!(This->Connections[index].advf & ADVF_NODATA)) {
689         TRACE("Calling IDataObject_GetData\n");
690         res = IDataObject_GetData(pDataObject,
691                                   &(This->Connections[index].fmat),
692                                   &stg);
693         TRACE("returns %08lx\n", res);
694       }
695       TRACE("Calling IAdviseSink_OnDataChange\n");
696       IAdviseSink_OnDataChange(This->Connections[index].sink,
697                                      &(This->Connections[index].fmat),
698                                      &stg);
699       TRACE("Done IAdviseSink_OnDataChange\n");
700       if(This->Connections[index].advf & ADVF_ONLYONCE) {
701         TRACE("Removing connection\n");
702         DataAdviseHolder_Unadvise(iface, index+1);
703       }
704     }
705   }
706   return S_OK;
707 }
708
709 /***********************************************************************
710  * API functions
711  */
712
713 /***********************************************************************
714  * CreateOleAdviseHolder [OLE32.@]
715  */
716 HRESULT WINAPI CreateOleAdviseHolder(
717   LPOLEADVISEHOLDER *ppOAHolder)
718 {
719   TRACE("(%p)\n", ppOAHolder);
720
721   /*
722    * Sanity check,
723    */
724   if (ppOAHolder==NULL)
725     return E_POINTER;
726
727   *ppOAHolder = OleAdviseHolderImpl_Constructor ();
728
729   if (*ppOAHolder != NULL)
730     return S_OK;
731
732   return E_OUTOFMEMORY;
733 }
734
735 /******************************************************************************
736  *              CreateDataAdviseHolder        [OLE32.@]
737  */
738 HRESULT WINAPI CreateDataAdviseHolder(
739   LPDATAADVISEHOLDER* ppDAHolder)
740 {
741   TRACE("(%p)\n", ppDAHolder);
742
743   /*
744    * Sanity check,
745    */
746   if (ppDAHolder==NULL)
747     return E_POINTER;
748
749   *ppDAHolder = DataAdviseHolder_Constructor();
750
751   if (*ppDAHolder != NULL)
752     return S_OK;
753
754   return E_OUTOFMEMORY;
755 }