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