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