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