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