Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[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   DWORD remote_connection;
355 } DataAdviseConnection;
356
357 typedef struct DataAdviseHolder
358 {
359   const IDataAdviseHolderVtbl *lpVtbl;
360
361   LONG                  ref;
362   DWORD                 maxCons;
363   DataAdviseConnection* Connections;
364 } DataAdviseHolder;
365
366 /* this connection has also has been advised to the delegate data object */
367 #define WINE_ADVF_REMOTE 0x80000000
368
369 /******************************************************************************
370  * DataAdviseHolder_Destructor
371  */
372 static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
373 {
374   DWORD index;
375   TRACE("%p\n", ptrToDestroy);
376
377   for (index = 0; index < ptrToDestroy->maxCons; index++)
378   {
379     if (ptrToDestroy->Connections[index].sink != NULL)
380     {
381       IAdviseSink_Release(ptrToDestroy->Connections[index].sink);
382       ptrToDestroy->Connections[index].sink = NULL;
383     }
384   }
385
386   HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections);
387   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
388 }
389
390 /************************************************************************
391  * DataAdviseHolder_QueryInterface (IUnknown)
392  *
393  * See Windows documentation for more details on IUnknown methods.
394  */
395 static HRESULT WINAPI DataAdviseHolder_QueryInterface(
396   IDataAdviseHolder*      iface,
397   REFIID                  riid,
398   void**                  ppvObject)
399 {
400   DataAdviseHolder *This = (DataAdviseHolder *)iface;
401   TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
402   /*
403    * Perform a sanity check on the parameters.
404    */
405   if ( (This==0) || (ppvObject==0) )
406     return E_INVALIDARG;
407
408   /*
409    * Initialize the return parameter.
410    */
411   *ppvObject = 0;
412
413   /*
414    * Compare the riid with the interface IDs implemented by this object.
415    */
416   if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) ||
417        (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0)  )
418   {
419     *ppvObject = iface;
420   }
421
422   /*
423    * Check that we obtained an interface.
424    */
425   if ((*ppvObject)==0)
426   {
427     return E_NOINTERFACE;
428   }
429
430   /*
431    * Query Interface always increases the reference count by one when it is
432    * successful.
433    */
434   IUnknown_AddRef((IUnknown*)*ppvObject);
435
436   return S_OK;
437 }
438
439 /************************************************************************
440  * DataAdviseHolder_AddRef (IUnknown)
441  *
442  * See Windows documentation for more details on IUnknown methods.
443  */
444 static ULONG WINAPI       DataAdviseHolder_AddRef(
445   IDataAdviseHolder*      iface)
446 {
447   DataAdviseHolder *This = (DataAdviseHolder *)iface;
448   TRACE("(%p) (ref=%ld)\n", This, This->ref);
449   return InterlockedIncrement(&This->ref);
450 }
451
452 /************************************************************************
453  * DataAdviseHolder_Release (IUnknown)
454  *
455  * See Windows documentation for more details on IUnknown methods.
456  */
457 static ULONG WINAPI DataAdviseHolder_Release(
458   IDataAdviseHolder*      iface)
459 {
460   DataAdviseHolder *This = (DataAdviseHolder *)iface;
461   ULONG ref;
462   TRACE("(%p) (ref=%ld)\n", This, This->ref);
463
464   /*
465    * Decrease the reference count on this object.
466    */
467   ref = InterlockedDecrement(&This->ref);
468
469   /*
470    * If the reference count goes down to 0, perform suicide.
471    */
472   if (ref==0) DataAdviseHolder_Destructor(This);
473
474   return ref;
475 }
476
477 /************************************************************************
478  * DataAdviseHolder_Advise
479  *
480  */
481 static HRESULT WINAPI DataAdviseHolder_Advise(
482   IDataAdviseHolder*      iface,
483   IDataObject*            pDataObject,
484   FORMATETC*              pFetc,
485   DWORD                   advf,
486   IAdviseSink*            pAdvise,
487   DWORD*                  pdwConnection)
488 {
489   DWORD index;
490
491   DataAdviseHolder *This = (DataAdviseHolder *)iface;
492
493   TRACE("(%p)->(%p, %p, %08lx, %p, %p)\n", This, pDataObject, pFetc, advf,
494         pAdvise, pdwConnection);
495   /*
496    * Sanity check
497    */
498   if (pdwConnection==NULL)
499     return E_POINTER;
500
501   *pdwConnection = 0;
502
503   /*
504    * Find a free spot in the array.
505    */
506   for (index = 0; index < This->maxCons; index++)
507   {
508     if (This->Connections[index].sink == NULL)
509       break;
510   }
511
512   /*
513    * If the array is full, we need to grow it.
514    */
515   if (index == This->maxCons)
516   {
517     This->maxCons+=INITIAL_SINKS;
518     This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
519                                     This->Connections,
520                                     This->maxCons*sizeof(DataAdviseConnection));
521   }
522   /*
523    * Store the new sink
524    */
525   This->Connections[index].sink = pAdvise;
526   memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC));
527   This->Connections[index].advf = advf & ~WINE_ADVF_REMOTE;
528
529   if (This->Connections[index].sink != NULL) {
530     IAdviseSink_AddRef(This->Connections[index].sink);
531     if(advf & ADVF_PRIMEFIRST) {
532       IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
533     }
534   }
535   /*
536    * Return the index as the cookie.
537    * Since 0 is not a valid cookie, we will increment by
538    * 1 the index in the table.
539    */
540   *pdwConnection = index+1;
541
542   return S_OK;
543 }
544
545 /******************************************************************************
546  * DataAdviseHolder_Unadvise
547  */
548 static HRESULT WINAPI     DataAdviseHolder_Unadvise(
549   IDataAdviseHolder*      iface,
550   DWORD                   dwConnection)
551 {
552   DataAdviseHolder *This = (DataAdviseHolder *)iface;
553
554   TRACE("(%p)->(%lu)\n", This, dwConnection);
555
556   /*
557    * So we don't return 0 as a cookie, the index was
558    * incremented by 1 in OleAdviseHolderImpl_Advise
559    * we have to compensate.
560    */
561   dwConnection--;
562
563   /*
564    * Check for invalid cookies.
565    */
566   if (dwConnection >= This->maxCons)
567     return OLE_E_NOCONNECTION;
568
569   if (This->Connections[dwConnection].sink == NULL)
570     return OLE_E_NOCONNECTION;
571
572   /*
573    * Release the sink and mark the spot in the list as free.
574    */
575   IAdviseSink_Release(This->Connections[dwConnection].sink);
576   memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection));
577   return S_OK;
578 }
579
580 static HRESULT WINAPI     DataAdviseHolder_EnumAdvise(
581   IDataAdviseHolder*      iface,
582   IEnumSTATDATA**         ppenumAdvise)
583 {
584   DataAdviseHolder *This = (DataAdviseHolder *)iface;
585
586   FIXME("(%p)->(%p)\n", This, ppenumAdvise);
587   return E_NOTIMPL;
588 }
589
590 /******************************************************************************
591  * DataAdviseHolder_SendOnDataChange
592  */
593 static HRESULT WINAPI     DataAdviseHolder_SendOnDataChange(
594   IDataAdviseHolder*      iface,
595   IDataObject*            pDataObject,
596   DWORD                   dwReserved,
597   DWORD                   advf)
598 {
599   DataAdviseHolder *This = (DataAdviseHolder *)iface;
600   DWORD index;
601   STGMEDIUM stg;
602   HRESULT res;
603
604   TRACE("(%p)->(%p,%08lx,%08lx)\n", This, pDataObject, dwReserved, advf);
605
606   for(index = 0; index < This->maxCons; index++) {
607     if(This->Connections[index].sink != NULL) {
608       if(!(This->Connections[index].advf & ADVF_NODATA)) {
609         TRACE("Calling IDataObject_GetData\n");
610         res = IDataObject_GetData(pDataObject,
611                                   &(This->Connections[index].fmat),
612                                   &stg);
613         TRACE("returns %08lx\n", res);
614       }
615       TRACE("Calling IAdviseSink_OnDataChange\n");
616       IAdviseSink_OnDataChange(This->Connections[index].sink,
617                                      &(This->Connections[index].fmat),
618                                      &stg);
619       TRACE("Done IAdviseSink_OnDataChange\n");
620       if(This->Connections[index].advf & ADVF_ONLYONCE) {
621         TRACE("Removing connection\n");
622         DataAdviseHolder_Unadvise(iface, index+1);
623       }
624     }
625   }
626   return S_OK;
627 }
628
629 /**************************************************************************
630  *  DataAdviseHolderImpl_VTable
631  */
632 static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
633 {
634   DataAdviseHolder_QueryInterface,
635   DataAdviseHolder_AddRef,
636   DataAdviseHolder_Release,
637   DataAdviseHolder_Advise,
638   DataAdviseHolder_Unadvise,
639   DataAdviseHolder_EnumAdvise,
640   DataAdviseHolder_SendOnDataChange
641 };
642
643 HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate)
644 {
645   DataAdviseHolder *This = (DataAdviseHolder *)iface;
646   DWORD index;
647   HRESULT hr = S_OK;
648
649   for(index = 0; index < This->maxCons; index++)
650   {
651     if(This->Connections[index].sink != NULL)
652     {
653       hr = IDataObject_DAdvise(pDelegate, &This->Connections[index].fmat,
654                                This->Connections[index].advf,
655                                This->Connections[index].sink,
656                                &This->Connections[index].remote_connection);
657       if (FAILED(hr)) break;
658       This->Connections[index].advf |= WINE_ADVF_REMOTE;
659     }
660   }
661   /* FIXME: store pDelegate somewhere */
662   return hr;
663 }
664
665 void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface)
666 {
667     /* FIXME: Unadvise all remote interfaces */
668 }
669
670 /******************************************************************************
671  * DataAdviseHolder_Constructor
672  */
673 static IDataAdviseHolder* DataAdviseHolder_Constructor(void)
674 {
675   DataAdviseHolder* newHolder;
676
677   newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder));
678
679   newHolder->lpVtbl = &DataAdviseHolderImpl_VTable;
680   newHolder->ref = 1;
681   newHolder->maxCons = INITIAL_SINKS;
682   newHolder->Connections = HeapAlloc(GetProcessHeap(),
683                                      HEAP_ZERO_MEMORY,
684                                      newHolder->maxCons *
685                                      sizeof(DataAdviseConnection));
686
687   TRACE("returning %p\n", newHolder);
688   return (IDataAdviseHolder*)newHolder;
689 }
690
691 /***********************************************************************
692  * API functions
693  */
694
695 /***********************************************************************
696  * CreateOleAdviseHolder [OLE32.@]
697  */
698 HRESULT WINAPI CreateOleAdviseHolder(
699   LPOLEADVISEHOLDER *ppOAHolder)
700 {
701   TRACE("(%p)\n", ppOAHolder);
702
703   /*
704    * Sanity check,
705    */
706   if (ppOAHolder==NULL)
707     return E_POINTER;
708
709   *ppOAHolder = OleAdviseHolderImpl_Constructor ();
710
711   if (*ppOAHolder != NULL)
712     return S_OK;
713
714   return E_OUTOFMEMORY;
715 }
716
717 /******************************************************************************
718  *              CreateDataAdviseHolder        [OLE32.@]
719  */
720 HRESULT WINAPI CreateDataAdviseHolder(
721   LPDATAADVISEHOLDER* ppDAHolder)
722 {
723   TRACE("(%p)\n", ppDAHolder);
724
725   /*
726    * Sanity check,
727    */
728   if (ppDAHolder==NULL)
729     return E_POINTER;
730
731   *ppDAHolder = DataAdviseHolder_Constructor();
732
733   if (*ppDAHolder != NULL)
734     return S_OK;
735
736   return E_OUTOFMEMORY;
737 }