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