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