xref: /reactos/dll/win32/ole32/oleobj.c (revision 0f5d91b7)
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 
23 #include <stdarg.h>
24 #include <string.h>
25 
26 #define COBJMACROS
27 #define NONAMELESSUNION
28 
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "wine/debug.h"
34 #include "ole2.h"
35 
36 #include "compobj_private.h"
37 
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 
40 #define INITIAL_SINKS 10
41 
release_statdata(STATDATA * data)42 static void release_statdata(STATDATA *data)
43 {
44     CoTaskMemFree(data->formatetc.ptd);
45     data->formatetc.ptd = NULL;
46 
47     if(data->pAdvSink)
48     {
49         IAdviseSink_Release(data->pAdvSink);
50         data->pAdvSink = NULL;
51     }
52 }
53 
copy_statdata(STATDATA * dst,const STATDATA * src)54 static HRESULT copy_statdata(STATDATA *dst, const STATDATA *src)
55 {
56     HRESULT hr;
57 
58     hr = copy_formatetc( &dst->formatetc, &src->formatetc );
59     if (FAILED(hr)) return hr;
60     dst->advf = src->advf;
61     dst->pAdvSink = src->pAdvSink;
62     if (dst->pAdvSink) IAdviseSink_AddRef( dst->pAdvSink );
63     dst->dwConnection = src->dwConnection;
64     return S_OK;
65 }
66 
67 /**************************************************************************
68  *  EnumSTATDATA Implementation
69  */
70 
71 typedef struct
72 {
73     IEnumSTATDATA IEnumSTATDATA_iface;
74     LONG ref;
75 
76     ULONG index;
77     DWORD num_of_elems;
78     STATDATA *statdata;
79     IUnknown *holder;
80 } EnumSTATDATA;
81 
impl_from_IEnumSTATDATA(IEnumSTATDATA * iface)82 static inline EnumSTATDATA *impl_from_IEnumSTATDATA(IEnumSTATDATA *iface)
83 {
84     return CONTAINING_RECORD(iface, EnumSTATDATA, IEnumSTATDATA_iface);
85 }
86 
EnumSTATDATA_QueryInterface(IEnumSTATDATA * iface,REFIID riid,void ** ppv)87 static HRESULT WINAPI EnumSTATDATA_QueryInterface(IEnumSTATDATA *iface, REFIID riid, void **ppv)
88 {
89     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
90     if (IsEqualIID(riid, &IID_IUnknown) ||
91         IsEqualIID(riid, &IID_IEnumSTATDATA))
92     {
93         IEnumSTATDATA_AddRef(iface);
94         *ppv = iface;
95         return S_OK;
96     }
97     return E_NOINTERFACE;
98 }
99 
EnumSTATDATA_AddRef(IEnumSTATDATA * iface)100 static ULONG WINAPI EnumSTATDATA_AddRef(IEnumSTATDATA *iface)
101 {
102     EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
103     TRACE("()\n");
104     return InterlockedIncrement(&This->ref);
105 }
106 
EnumSTATDATA_Release(IEnumSTATDATA * iface)107 static ULONG WINAPI EnumSTATDATA_Release(IEnumSTATDATA *iface)
108 {
109     EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
110     LONG refs = InterlockedDecrement(&This->ref);
111     TRACE("()\n");
112     if (!refs)
113     {
114         DWORD i;
115         for(i = 0; i < This->num_of_elems; i++)
116             release_statdata(This->statdata + i);
117         HeapFree(GetProcessHeap(), 0, This->statdata);
118         if (This->holder) IUnknown_Release(This->holder);
119         HeapFree(GetProcessHeap(), 0, This);
120     }
121     return refs;
122 }
123 
EnumSTATDATA_Next(IEnumSTATDATA * iface,ULONG num,LPSTATDATA data,ULONG * fetched)124 static HRESULT WINAPI EnumSTATDATA_Next(IEnumSTATDATA *iface, ULONG num, LPSTATDATA data,
125                                         ULONG *fetched)
126 {
127     EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
128     DWORD count = 0;
129     HRESULT hr = S_OK;
130 
131     TRACE("(%d, %p, %p)\n", num, data, fetched);
132 
133     while(num--)
134     {
135         if (This->index >= This->num_of_elems)
136         {
137             hr = S_FALSE;
138             break;
139         }
140 
141         copy_statdata(data + count, This->statdata + This->index);
142 
143         count++;
144         This->index++;
145     }
146 
147     if (fetched) *fetched = count;
148 
149     return hr;
150 }
151 
EnumSTATDATA_Skip(IEnumSTATDATA * iface,ULONG num)152 static HRESULT WINAPI EnumSTATDATA_Skip(IEnumSTATDATA *iface, ULONG num)
153 {
154     EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
155 
156     TRACE("(%d)\n", num);
157 
158     if(This->index + num >= This->num_of_elems)
159     {
160         This->index = This->num_of_elems;
161         return S_FALSE;
162     }
163 
164     This->index += num;
165     return S_OK;
166 }
167 
EnumSTATDATA_Reset(IEnumSTATDATA * iface)168 static HRESULT WINAPI EnumSTATDATA_Reset(IEnumSTATDATA *iface)
169 {
170     EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
171 
172     TRACE("()\n");
173 
174     This->index = 0;
175     return S_OK;
176 }
177 
EnumSTATDATA_Clone(IEnumSTATDATA * iface,IEnumSTATDATA ** ppenum)178 static HRESULT WINAPI EnumSTATDATA_Clone(IEnumSTATDATA *iface, IEnumSTATDATA **ppenum)
179 {
180     EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
181 
182     return EnumSTATDATA_Construct(This->holder, This->index, This->num_of_elems, This->statdata,
183                                   TRUE, ppenum);
184 }
185 
186 static const IEnumSTATDATAVtbl EnumSTATDATA_VTable =
187 {
188     EnumSTATDATA_QueryInterface,
189     EnumSTATDATA_AddRef,
190     EnumSTATDATA_Release,
191     EnumSTATDATA_Next,
192     EnumSTATDATA_Skip,
193     EnumSTATDATA_Reset,
194     EnumSTATDATA_Clone
195 };
196 
EnumSTATDATA_Construct(IUnknown * holder,ULONG index,DWORD array_len,STATDATA * data,BOOL copy,IEnumSTATDATA ** ppenum)197 HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data,
198                                BOOL copy, IEnumSTATDATA **ppenum)
199 {
200     EnumSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
201     DWORD i, count;
202 
203     if (!This) return E_OUTOFMEMORY;
204 
205     This->IEnumSTATDATA_iface.lpVtbl = &EnumSTATDATA_VTable;
206     This->ref = 1;
207     This->index = index;
208 
209     if (copy)
210     {
211         This->statdata = HeapAlloc(GetProcessHeap(), 0, array_len * sizeof(*This->statdata));
212         if(!This->statdata)
213         {
214             HeapFree(GetProcessHeap(), 0, This);
215             return E_OUTOFMEMORY;
216         }
217 
218         for(i = 0, count = 0; i < array_len; i++)
219         {
220             if(data[i].pAdvSink)
221             {
222                 copy_statdata(This->statdata + count, data + i);
223                 count++;
224             }
225         }
226     }
227     else
228     {
229         This->statdata = data;
230         count = array_len;
231     }
232 
233     This->num_of_elems = count;
234     This->holder = holder;
235     if (holder) IUnknown_AddRef(holder);
236     *ppenum = &This->IEnumSTATDATA_iface;
237     return S_OK;
238 }
239 
240 /**************************************************************************
241  *  OleAdviseHolder Implementation
242  */
243 typedef struct
244 {
245     IOleAdviseHolder IOleAdviseHolder_iface;
246 
247     LONG ref;
248 
249     DWORD max_cons;
250     STATDATA *connections;
251 } OleAdviseHolderImpl;
252 
impl_from_IOleAdviseHolder(IOleAdviseHolder * iface)253 static inline OleAdviseHolderImpl *impl_from_IOleAdviseHolder(IOleAdviseHolder *iface)
254 {
255     return CONTAINING_RECORD(iface, OleAdviseHolderImpl, IOleAdviseHolder_iface);
256 }
257 
258 /**************************************************************************
259  *  OleAdviseHolderImpl_Destructor
260  */
OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl * This)261 static void OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl *This)
262 {
263     DWORD index;
264     TRACE("%p\n", This);
265 
266     for (index = 0; index < This->max_cons; index++)
267     {
268         if (This->connections[index].pAdvSink != NULL)
269             release_statdata(This->connections + index);
270     }
271 
272     HeapFree(GetProcessHeap(), 0, This->connections);
273     HeapFree(GetProcessHeap(), 0, This);
274 }
275 
276 /**************************************************************************
277  *  OleAdviseHolderImpl_QueryInterface
278  */
OleAdviseHolderImpl_QueryInterface(IOleAdviseHolder * iface,REFIID iid,void ** obj)279 static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(IOleAdviseHolder *iface,
280                                                          REFIID iid, void **obj)
281 {
282   OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
283   TRACE("(%p)->(%s,%p)\n",This, debugstr_guid(iid), obj);
284 
285   if (obj == NULL)
286     return E_POINTER;
287 
288   *obj = NULL;
289 
290   if (IsEqualIID(iid, &IID_IUnknown) ||
291       IsEqualIID(iid, &IID_IOleAdviseHolder))
292   {
293     *obj = &This->IOleAdviseHolder_iface;
294   }
295 
296   if(*obj == NULL)
297     return E_NOINTERFACE;
298 
299   IUnknown_AddRef((IUnknown*)*obj);
300 
301   return S_OK;
302 }
303 
304 /******************************************************************************
305  * OleAdviseHolderImpl_AddRef
306  */
OleAdviseHolderImpl_AddRef(IOleAdviseHolder * iface)307 static ULONG WINAPI OleAdviseHolderImpl_AddRef(IOleAdviseHolder *iface)
308 {
309   OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
310   ULONG ref = InterlockedIncrement(&This->ref);
311 
312   TRACE("(%p)->(ref=%d)\n", This, ref - 1);
313 
314   return ref;
315 }
316 
317 /******************************************************************************
318  * OleAdviseHolderImpl_Release
319  */
OleAdviseHolderImpl_Release(IOleAdviseHolder * iface)320 static ULONG WINAPI OleAdviseHolderImpl_Release(IOleAdviseHolder *iface)
321 {
322   OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
323   ULONG ref;
324   TRACE("(%p)->(ref=%d)\n", This, This->ref);
325   ref = InterlockedDecrement(&This->ref);
326 
327   if (ref == 0) OleAdviseHolderImpl_Destructor(This);
328 
329   return ref;
330 }
331 
332 /******************************************************************************
333  * OleAdviseHolderImpl_Advise
334  */
OleAdviseHolderImpl_Advise(IOleAdviseHolder * iface,IAdviseSink * pAdvise,DWORD * pdwConnection)335 static HRESULT WINAPI OleAdviseHolderImpl_Advise(IOleAdviseHolder *iface,
336                                                  IAdviseSink *pAdvise,
337                                                  DWORD *pdwConnection)
338 {
339   DWORD index;
340   OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
341   STATDATA new_conn;
342   static const FORMATETC empty_fmtetc = {0, NULL, 0, -1, 0};
343 
344   TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection);
345 
346   if (pdwConnection==NULL)
347     return E_POINTER;
348 
349   *pdwConnection = 0;
350 
351   for (index = 0; index < This->max_cons; index++)
352   {
353     if (This->connections[index].pAdvSink == NULL)
354       break;
355   }
356 
357   if (index == This->max_cons)
358   {
359     This->max_cons += INITIAL_SINKS;
360     This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->connections,
361                                     This->max_cons * sizeof(*This->connections));
362   }
363 
364   new_conn.pAdvSink = pAdvise;
365   new_conn.advf = 0;
366   new_conn.formatetc = empty_fmtetc;
367   new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */
368 
369   copy_statdata(This->connections + index, &new_conn);
370 
371   *pdwConnection = new_conn.dwConnection;
372 
373   return S_OK;
374 }
375 
376 /******************************************************************************
377  * OleAdviseHolderImpl_Unadvise
378  */
OleAdviseHolderImpl_Unadvise(IOleAdviseHolder * iface,DWORD dwConnection)379 static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(IOleAdviseHolder *iface,
380                                                    DWORD dwConnection)
381 {
382   OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
383   DWORD index;
384 
385   TRACE("(%p)->(%u)\n", This, dwConnection);
386 
387   /* The connection number is 1 more than the index, see OleAdviseHolder_Advise */
388   index = dwConnection - 1;
389 
390   if (index >= This->max_cons || This->connections[index].pAdvSink == NULL)
391      return OLE_E_NOCONNECTION;
392 
393   release_statdata(This->connections + index);
394 
395   return S_OK;
396 }
397 
398 /******************************************************************************
399  * OleAdviseHolderImpl_EnumAdvise
400  */
OleAdviseHolderImpl_EnumAdvise(IOleAdviseHolder * iface,IEnumSTATDATA ** enum_advise)401 static HRESULT WINAPI OleAdviseHolderImpl_EnumAdvise(IOleAdviseHolder *iface, IEnumSTATDATA **enum_advise)
402 {
403     OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
404     IUnknown *unk;
405     HRESULT hr;
406 
407     TRACE("(%p)->(%p)\n", This, enum_advise);
408 
409     IOleAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk);
410     hr = EnumSTATDATA_Construct(unk, 0, This->max_cons, This->connections, TRUE, enum_advise);
411     IUnknown_Release(unk);
412     return hr;
413 }
414 
415 /******************************************************************************
416  * OleAdviseHolderImpl_SendOnRename
417  */
OleAdviseHolderImpl_SendOnRename(IOleAdviseHolder * iface,IMoniker * pmk)418 static HRESULT WINAPI OleAdviseHolderImpl_SendOnRename(IOleAdviseHolder *iface, IMoniker *pmk)
419 {
420     IEnumSTATDATA *pEnum;
421     HRESULT hr;
422 
423     TRACE("(%p)->(%p)\n", iface, pmk);
424 
425     hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
426     if (SUCCEEDED(hr))
427     {
428         STATDATA statdata;
429         while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
430         {
431             IAdviseSink_OnRename(statdata.pAdvSink, pmk);
432 
433             IAdviseSink_Release(statdata.pAdvSink);
434         }
435         IEnumSTATDATA_Release(pEnum);
436     }
437 
438     return hr;
439 }
440 
441 /******************************************************************************
442  * OleAdviseHolderImpl_SendOnSave
443  */
OleAdviseHolderImpl_SendOnSave(IOleAdviseHolder * iface)444 static HRESULT WINAPI OleAdviseHolderImpl_SendOnSave(IOleAdviseHolder *iface)
445 {
446     IEnumSTATDATA *pEnum;
447     HRESULT hr;
448 
449     TRACE("(%p)->()\n", iface);
450 
451     hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
452     if (SUCCEEDED(hr))
453     {
454         STATDATA statdata;
455         while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
456         {
457             IAdviseSink_OnSave(statdata.pAdvSink);
458 
459             IAdviseSink_Release(statdata.pAdvSink);
460         }
461         IEnumSTATDATA_Release(pEnum);
462     }
463 
464     return hr;
465 }
466 
467 /******************************************************************************
468  * OleAdviseHolderImpl_SendOnClose
469  */
OleAdviseHolderImpl_SendOnClose(IOleAdviseHolder * iface)470 static HRESULT WINAPI OleAdviseHolderImpl_SendOnClose(IOleAdviseHolder *iface)
471 {
472     IEnumSTATDATA *pEnum;
473     HRESULT hr;
474 
475     TRACE("(%p)->()\n", iface);
476 
477     hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
478     if (SUCCEEDED(hr))
479     {
480         STATDATA statdata;
481         while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
482         {
483             IAdviseSink_OnClose(statdata.pAdvSink);
484 
485             IAdviseSink_Release(statdata.pAdvSink);
486         }
487         IEnumSTATDATA_Release(pEnum);
488     }
489 
490     return hr;
491 }
492 
493 /**************************************************************************
494  *  OleAdviseHolderImpl_VTable
495  */
496 static const IOleAdviseHolderVtbl oahvt =
497 {
498     OleAdviseHolderImpl_QueryInterface,
499     OleAdviseHolderImpl_AddRef,
500     OleAdviseHolderImpl_Release,
501     OleAdviseHolderImpl_Advise,
502     OleAdviseHolderImpl_Unadvise,
503     OleAdviseHolderImpl_EnumAdvise,
504     OleAdviseHolderImpl_SendOnRename,
505     OleAdviseHolderImpl_SendOnSave,
506     OleAdviseHolderImpl_SendOnClose
507 };
508 
509 /**************************************************************************
510  *  OleAdviseHolderImpl_Constructor
511  */
512 
OleAdviseHolderImpl_Constructor(void)513 static IOleAdviseHolder *OleAdviseHolderImpl_Constructor(void)
514 {
515   OleAdviseHolderImpl* lpoah;
516 
517   lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl));
518 
519   lpoah->IOleAdviseHolder_iface.lpVtbl = &oahvt;
520   lpoah->ref = 1;
521   lpoah->max_cons = INITIAL_SINKS;
522   lpoah->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
523                                  lpoah->max_cons * sizeof(*lpoah->connections));
524 
525   TRACE("returning %p\n",  &lpoah->IOleAdviseHolder_iface);
526   return &lpoah->IOleAdviseHolder_iface;
527 }
528 
529 /**************************************************************************
530  *  DataAdviseHolder Implementation
531  */
532 typedef struct
533 {
534   IDataAdviseHolder     IDataAdviseHolder_iface;
535 
536   LONG                  ref;
537   DWORD                 maxCons;
538   STATDATA*             connections;
539   DWORD*                remote_connections;
540   IDataObject*          delegate;
541 } DataAdviseHolder;
542 
543 /* this connection has also has been advised to the delegate data object */
544 #define WINE_ADVF_REMOTE 0x80000000
545 
impl_from_IDataAdviseHolder(IDataAdviseHolder * iface)546 static inline DataAdviseHolder *impl_from_IDataAdviseHolder(IDataAdviseHolder *iface)
547 {
548     return CONTAINING_RECORD(iface, DataAdviseHolder, IDataAdviseHolder_iface);
549 }
550 
551 /******************************************************************************
552  * DataAdviseHolder_Destructor
553  */
DataAdviseHolder_Destructor(DataAdviseHolder * ptrToDestroy)554 static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
555 {
556   DWORD index;
557   TRACE("%p\n", ptrToDestroy);
558 
559   for (index = 0; index < ptrToDestroy->maxCons; index++)
560   {
561     if (ptrToDestroy->connections[index].pAdvSink != NULL)
562     {
563       if (ptrToDestroy->delegate &&
564           (ptrToDestroy->connections[index].advf & WINE_ADVF_REMOTE))
565         IDataObject_DUnadvise(ptrToDestroy->delegate,
566           ptrToDestroy->remote_connections[index]);
567 
568       release_statdata(ptrToDestroy->connections + index);
569     }
570   }
571 
572   HeapFree(GetProcessHeap(), 0, ptrToDestroy->remote_connections);
573   HeapFree(GetProcessHeap(), 0, ptrToDestroy->connections);
574   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
575 }
576 
577 /************************************************************************
578  * DataAdviseHolder_QueryInterface (IUnknown)
579  */
DataAdviseHolder_QueryInterface(IDataAdviseHolder * iface,REFIID riid,void ** ppvObject)580 static HRESULT WINAPI DataAdviseHolder_QueryInterface(IDataAdviseHolder *iface,
581                                                       REFIID riid, void **ppvObject)
582 {
583   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
584   TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
585 
586   if ( (This==0) || (ppvObject==0) )
587     return E_INVALIDARG;
588 
589   *ppvObject = 0;
590 
591   if ( IsEqualIID(&IID_IUnknown, riid) ||
592        IsEqualIID(&IID_IDataAdviseHolder, riid)  )
593   {
594     *ppvObject = iface;
595   }
596 
597   if ((*ppvObject)==0)
598   {
599     return E_NOINTERFACE;
600   }
601 
602   IUnknown_AddRef((IUnknown*)*ppvObject);
603   return S_OK;
604 }
605 
606 /************************************************************************
607  * DataAdviseHolder_AddRef (IUnknown)
608  */
DataAdviseHolder_AddRef(IDataAdviseHolder * iface)609 static ULONG WINAPI DataAdviseHolder_AddRef(IDataAdviseHolder *iface)
610 {
611   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
612   TRACE("(%p) (ref=%d)\n", This, This->ref);
613   return InterlockedIncrement(&This->ref);
614 }
615 
616 /************************************************************************
617  * DataAdviseHolder_Release (IUnknown)
618  */
DataAdviseHolder_Release(IDataAdviseHolder * iface)619 static ULONG WINAPI DataAdviseHolder_Release(IDataAdviseHolder *iface)
620 {
621   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
622   ULONG ref;
623   TRACE("(%p) (ref=%d)\n", This, This->ref);
624 
625   ref = InterlockedDecrement(&This->ref);
626   if (ref==0) DataAdviseHolder_Destructor(This);
627 
628   return ref;
629 }
630 
631 /************************************************************************
632  * DataAdviseHolder_Advise
633  *
634  */
DataAdviseHolder_Advise(IDataAdviseHolder * iface,IDataObject * pDataObject,FORMATETC * pFetc,DWORD advf,IAdviseSink * pAdvise,DWORD * pdwConnection)635 static HRESULT WINAPI DataAdviseHolder_Advise(IDataAdviseHolder *iface,
636                                               IDataObject *pDataObject, FORMATETC *pFetc,
637                                               DWORD advf, IAdviseSink *pAdvise,
638                                               DWORD *pdwConnection)
639 {
640   DWORD index;
641   STATDATA new_conn;
642   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
643 
644   TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf,
645 	pAdvise, pdwConnection);
646 
647   if (pdwConnection==NULL)
648     return E_POINTER;
649 
650   *pdwConnection = 0;
651 
652   for (index = 0; index < This->maxCons; index++)
653   {
654     if (This->connections[index].pAdvSink == NULL)
655       break;
656   }
657 
658   if (index == This->maxCons)
659   {
660     This->maxCons+=INITIAL_SINKS;
661     This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
662                                     This->connections,
663                                     This->maxCons * sizeof(*This->connections));
664     This->remote_connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
665                                            This->remote_connections,
666                                            This->maxCons * sizeof(*This->remote_connections));
667   }
668 
669   new_conn.pAdvSink = pAdvise;
670   new_conn.advf = advf & ~WINE_ADVF_REMOTE;
671   new_conn.formatetc = *pFetc;
672   new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */
673 
674   copy_statdata(This->connections + index, &new_conn);
675 
676   if (This->connections[index].pAdvSink != NULL)
677   {
678     /* if we are already connected advise the remote object */
679     if (This->delegate)
680     {
681         HRESULT hr;
682 
683         hr = IDataObject_DAdvise(This->delegate, &new_conn.formatetc,
684                                  new_conn.advf, new_conn.pAdvSink,
685                                  &This->remote_connections[index]);
686         if (FAILED(hr))
687         {
688             IDataAdviseHolder_Unadvise(iface, new_conn.dwConnection);
689             return hr;
690         }
691         This->connections[index].advf |= WINE_ADVF_REMOTE;
692     }
693     else if(advf & ADVF_PRIMEFIRST)
694       /* only do this if we have no delegate, since in the above case the
695        * delegate will do the priming for us */
696       IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
697   }
698 
699   *pdwConnection = new_conn.dwConnection;
700 
701   return S_OK;
702 }
703 
704 /******************************************************************************
705  * DataAdviseHolder_Unadvise
706  */
DataAdviseHolder_Unadvise(IDataAdviseHolder * iface,DWORD dwConnection)707 static HRESULT WINAPI DataAdviseHolder_Unadvise(IDataAdviseHolder *iface,
708                                                 DWORD dwConnection)
709 {
710   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
711   DWORD index;
712   TRACE("(%p)->(%u)\n", This, dwConnection);
713 
714   /* The connection number is 1 more than the index, see DataAdviseHolder_Advise */
715   index = dwConnection - 1;
716 
717   if (index >= This->maxCons || This->connections[index].pAdvSink == NULL)
718      return OLE_E_NOCONNECTION;
719 
720   if (This->delegate && This->connections[index].advf & WINE_ADVF_REMOTE)
721   {
722     IDataObject_DUnadvise(This->delegate, This->remote_connections[index]);
723     This->remote_connections[index] = 0;
724   }
725 
726   release_statdata(This->connections + index);
727 
728   return S_OK;
729 }
730 
731 /******************************************************************************
732  * DataAdviseHolder_EnumAdvise
733  */
DataAdviseHolder_EnumAdvise(IDataAdviseHolder * iface,IEnumSTATDATA ** enum_advise)734 static HRESULT WINAPI DataAdviseHolder_EnumAdvise(IDataAdviseHolder *iface,
735                                                   IEnumSTATDATA **enum_advise)
736 {
737     DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
738     IUnknown *unk;
739     HRESULT hr;
740 
741     TRACE("(%p)->(%p)\n", This, enum_advise);
742 
743     IDataAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk);
744     hr = EnumSTATDATA_Construct(unk, 0, This->maxCons, This->connections, TRUE, enum_advise);
745     IUnknown_Release(unk);
746     return hr;
747 }
748 
749 /******************************************************************************
750  * DataAdviseHolder_SendOnDataChange
751  */
DataAdviseHolder_SendOnDataChange(IDataAdviseHolder * iface,IDataObject * data_obj,DWORD dwReserved,DWORD advf)752 static HRESULT WINAPI DataAdviseHolder_SendOnDataChange(IDataAdviseHolder *iface,
753                                                         IDataObject *data_obj,
754                                                         DWORD dwReserved, DWORD advf)
755 {
756     IEnumSTATDATA *pEnum;
757     HRESULT hr;
758 
759     TRACE("(%p)->(%p, %08x, %08x)\n", iface, data_obj, dwReserved, advf);
760 
761     hr = IDataAdviseHolder_EnumAdvise(iface, &pEnum);
762     if (SUCCEEDED(hr))
763     {
764         STATDATA statdata;
765         while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
766         {
767             STGMEDIUM stg;
768             stg.tymed = TYMED_NULL;
769             stg.u.pstg = NULL;
770             stg.pUnkForRelease = NULL;
771 
772             if(!(statdata.advf & ADVF_NODATA))
773             {
774                 hr = IDataObject_GetData(data_obj, &statdata.formatetc, &stg);
775             }
776 
777             IAdviseSink_OnDataChange(statdata.pAdvSink, &statdata.formatetc, &stg);
778 
779             if(statdata.advf & ADVF_ONLYONCE)
780             {
781                 IDataAdviseHolder_Unadvise(iface, statdata.dwConnection);
782             }
783 
784             release_statdata(&statdata);
785         }
786         IEnumSTATDATA_Release(pEnum);
787     }
788 
789     return S_OK;
790 }
791 
792 /**************************************************************************
793  *  DataAdviseHolderImpl_VTable
794  */
795 static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
796 {
797   DataAdviseHolder_QueryInterface,
798   DataAdviseHolder_AddRef,
799   DataAdviseHolder_Release,
800   DataAdviseHolder_Advise,
801   DataAdviseHolder_Unadvise,
802   DataAdviseHolder_EnumAdvise,
803   DataAdviseHolder_SendOnDataChange
804 };
805 
DataAdviseHolder_OnConnect(IDataAdviseHolder * iface,IDataObject * pDelegate)806 HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate)
807 {
808   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
809   DWORD index;
810   HRESULT hr = S_OK;
811 
812   for(index = 0; index < This->maxCons; index++)
813   {
814     if(This->connections[index].pAdvSink != NULL)
815     {
816       hr = IDataObject_DAdvise(pDelegate, &This->connections[index].formatetc,
817                                This->connections[index].advf,
818                                This->connections[index].pAdvSink,
819                                &This->remote_connections[index]);
820       if (FAILED(hr)) break;
821       This->connections[index].advf |= WINE_ADVF_REMOTE;
822     }
823   }
824   This->delegate = pDelegate;
825   return hr;
826 }
827 
DataAdviseHolder_OnDisconnect(IDataAdviseHolder * iface)828 void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface)
829 {
830   DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
831   DWORD index;
832 
833   for(index = 0; index < This->maxCons; index++)
834   {
835     if((This->connections[index].pAdvSink != NULL) &&
836        (This->connections[index].advf & WINE_ADVF_REMOTE))
837     {
838       IDataObject_DUnadvise(This->delegate, This->remote_connections[index]);
839       This->remote_connections[index] = 0;
840       This->connections[index].advf &= ~WINE_ADVF_REMOTE;
841     }
842   }
843   This->delegate = NULL;
844 }
845 
846 /******************************************************************************
847  * DataAdviseHolder_Constructor
848  */
DataAdviseHolder_Constructor(void)849 static IDataAdviseHolder *DataAdviseHolder_Constructor(void)
850 {
851   DataAdviseHolder* newHolder;
852 
853   newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder));
854 
855   newHolder->IDataAdviseHolder_iface.lpVtbl = &DataAdviseHolderImpl_VTable;
856   newHolder->ref = 1;
857   newHolder->maxCons = INITIAL_SINKS;
858   newHolder->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
859                                      newHolder->maxCons * sizeof(*newHolder->connections));
860   newHolder->remote_connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
861                                             newHolder->maxCons * sizeof(*newHolder->remote_connections));
862   newHolder->delegate = NULL;
863 
864   TRACE("returning %p\n", &newHolder->IDataAdviseHolder_iface);
865   return &newHolder->IDataAdviseHolder_iface;
866 }
867 
868 /***********************************************************************
869  * API functions
870  */
871 
872 /***********************************************************************
873  * CreateOleAdviseHolder [OLE32.@]
874  */
CreateOleAdviseHolder(IOleAdviseHolder ** ppOAHolder)875 HRESULT WINAPI CreateOleAdviseHolder(IOleAdviseHolder **ppOAHolder)
876 {
877   TRACE("(%p)\n", ppOAHolder);
878 
879   if (ppOAHolder==NULL)
880     return E_POINTER;
881 
882   *ppOAHolder = OleAdviseHolderImpl_Constructor ();
883 
884   if (*ppOAHolder != NULL)
885     return S_OK;
886 
887   return E_OUTOFMEMORY;
888 }
889 
890 /******************************************************************************
891  *              CreateDataAdviseHolder        [OLE32.@]
892  */
CreateDataAdviseHolder(IDataAdviseHolder ** ppDAHolder)893 HRESULT WINAPI CreateDataAdviseHolder(IDataAdviseHolder **ppDAHolder)
894 {
895   TRACE("(%p)\n", ppDAHolder);
896 
897   if (ppDAHolder==NULL)
898     return E_POINTER;
899 
900   *ppDAHolder = DataAdviseHolder_Constructor();
901 
902   if (*ppDAHolder != NULL)
903     return S_OK;
904 
905   return E_OUTOFMEMORY;
906 }
907