Finish the Wine sync. These components are not just rc file changes
[reactos.git] / reactos / dll / win32 / 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., 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
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 #include "compobj_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38
39 #define INITIAL_SINKS 10
40
41 /**************************************************************************
42 * OleAdviseHolderImpl Implementation
43 */
44 typedef struct OleAdviseHolderImpl
45 {
46 const IOleAdviseHolderVtbl *lpVtbl;
47
48 LONG ref;
49
50 DWORD maxSinks;
51 IAdviseSink** arrayOfSinks;
52
53 } OleAdviseHolderImpl;
54
55 static HRESULT EnumOleSTATDATA_Construct(OleAdviseHolderImpl *pOleAdviseHolder, ULONG index, IEnumSTATDATA **ppenum);
56
57 typedef struct
58 {
59 const IEnumSTATDATAVtbl *lpvtbl;
60 LONG ref;
61
62 ULONG index;
63 OleAdviseHolderImpl *pOleAdviseHolder;
64 } EnumOleSTATDATA;
65
66 static HRESULT WINAPI EnumOleSTATDATA_QueryInterface(
67 IEnumSTATDATA *iface, REFIID riid, void **ppv)
68 {
69 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
70 if (IsEqualIID(riid, &IID_IUnknown) ||
71 IsEqualIID(riid, &IID_IEnumSTATDATA))
72 {
73 IUnknown_AddRef(iface);
74 *ppv = iface;
75 return S_OK;
76 }
77 return E_NOINTERFACE;
78 }
79
80 static ULONG WINAPI EnumOleSTATDATA_AddRef(
81 IEnumSTATDATA *iface)
82 {
83 EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface;
84 TRACE("()\n");
85 return InterlockedIncrement(&This->ref);
86 }
87
88 static ULONG WINAPI EnumOleSTATDATA_Release(
89 IEnumSTATDATA *iface)
90 {
91 EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface;
92 LONG refs = InterlockedDecrement(&This->ref);
93 TRACE("()\n");
94 if (!refs)
95 {
96 IOleAdviseHolder_Release((IOleAdviseHolder *)This->pOleAdviseHolder);
97 HeapFree(GetProcessHeap(), 0, This);
98 }
99 return refs;
100 }
101
102 static HRESULT WINAPI EnumOleSTATDATA_Next(
103 IEnumSTATDATA *iface, ULONG celt, LPSTATDATA rgelt,
104 ULONG *pceltFetched)
105 {
106 EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface;
107 HRESULT hr = S_OK;
108
109 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
110
111 if (pceltFetched)
112 *pceltFetched = 0;
113
114 for (; celt; celt--, rgelt++)
115 {
116 while ((This->index < This->pOleAdviseHolder->maxSinks) &&
117 !This->pOleAdviseHolder->arrayOfSinks[This->index])
118 {
119 This->index++;
120 }
121 if (This->index >= This->pOleAdviseHolder->maxSinks)
122 {
123 hr = S_FALSE;
124 break;
125 }
126
127 memset(&rgelt->formatetc, 0, sizeof(rgelt->formatetc));
128 rgelt->advf = 0;
129 rgelt->pAdvSink = This->pOleAdviseHolder->arrayOfSinks[This->index];
130 IAdviseSink_AddRef(rgelt->pAdvSink);
131 rgelt->dwConnection = This->index;
132
133 if (pceltFetched)
134 (*pceltFetched)++;
135 This->index++;
136 }
137 return hr;
138 }
139
140 static HRESULT WINAPI EnumOleSTATDATA_Skip(
141 IEnumSTATDATA *iface, ULONG celt)
142 {
143 EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface;
144
145 TRACE("(%d)\n", celt);
146
147 for (; celt; celt--)
148 {
149 while ((This->index < This->pOleAdviseHolder->maxSinks) &&
150 !This->pOleAdviseHolder->arrayOfSinks[This->index])
151 {
152 This->index++;
153 }
154 if (This->index >= This->pOleAdviseHolder->maxSinks)
155 return S_FALSE;
156 This->index++;
157 }
158 return S_OK;
159 }
160
161 static HRESULT WINAPI EnumOleSTATDATA_Reset(
162 IEnumSTATDATA *iface)
163 {
164 EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface;
165
166 TRACE("()\n");
167
168 This->index = 0;
169 return S_OK;
170 }
171
172 static HRESULT WINAPI EnumOleSTATDATA_Clone(
173 IEnumSTATDATA *iface,
174 IEnumSTATDATA **ppenum)
175 {
176 EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface;
177 return EnumOleSTATDATA_Construct(This->pOleAdviseHolder, This->index, ppenum);
178 }
179
180 static const IEnumSTATDATAVtbl EnumOleSTATDATA_VTable =
181 {
182 EnumOleSTATDATA_QueryInterface,
183 EnumOleSTATDATA_AddRef,
184 EnumOleSTATDATA_Release,
185 EnumOleSTATDATA_Next,
186 EnumOleSTATDATA_Skip,
187 EnumOleSTATDATA_Reset,
188 EnumOleSTATDATA_Clone
189 };
190
191 static HRESULT EnumOleSTATDATA_Construct(OleAdviseHolderImpl *pOleAdviseHolder, ULONG index, IEnumSTATDATA **ppenum)
192 {
193 EnumOleSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
194 if (!This)
195 return E_OUTOFMEMORY;
196 This->lpvtbl = &EnumOleSTATDATA_VTable;
197 This->ref = 1;
198 This->index = index;
199 This->pOleAdviseHolder = pOleAdviseHolder;
200 IOleAdviseHolder_AddRef((IOleAdviseHolder *)pOleAdviseHolder);
201 *ppenum = (IEnumSTATDATA *)&This->lpvtbl;
202 return S_OK;
203 }
204
205 /**************************************************************************
206 * OleAdviseHolderImpl_Destructor
207 */
208 static void OleAdviseHolderImpl_Destructor(
209 OleAdviseHolderImpl* ptrToDestroy)
210 {
211 DWORD index;
212 TRACE("%p\n", ptrToDestroy);
213
214 for (index = 0; index < ptrToDestroy->maxSinks; index++)
215 {
216 if (ptrToDestroy->arrayOfSinks[index]!=0)
217 {
218 IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]);
219 ptrToDestroy->arrayOfSinks[index] = NULL;
220 }
221 }
222
223 HeapFree(GetProcessHeap(),
224 0,
225 ptrToDestroy->arrayOfSinks);
226
227
228 HeapFree(GetProcessHeap(),
229 0,
230 ptrToDestroy);
231 }
232
233 /**************************************************************************
234 * OleAdviseHolderImpl_QueryInterface
235 */
236 static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(
237 LPOLEADVISEHOLDER iface,
238 REFIID riid,
239 LPVOID* ppvObj)
240 {
241 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
242 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObj);
243 /*
244 * Sanity check
245 */
246 if (ppvObj==NULL)
247 return E_POINTER;
248
249 *ppvObj = NULL;
250
251 if (IsEqualIID(riid, &IID_IUnknown))
252 {
253 /* IUnknown */
254 *ppvObj = This;
255 }
256 else if(IsEqualIID(riid, &IID_IOleAdviseHolder))
257 {
258 /* IOleAdviseHolder */
259 *ppvObj = This;
260 }
261
262 if(*ppvObj == NULL)
263 return E_NOINTERFACE;
264
265 /*
266 * A successful QI always increments the reference count.
267 */
268 IUnknown_AddRef((IUnknown*)*ppvObj);
269
270 return S_OK;
271 }
272
273 /******************************************************************************
274 * OleAdviseHolderImpl_AddRef
275 */
276 static ULONG WINAPI OleAdviseHolderImpl_AddRef(
277 LPOLEADVISEHOLDER iface)
278 {
279 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
280 ULONG ref = InterlockedIncrement(&This->ref);
281
282 TRACE("(%p)->(ref=%d)\n", This, ref - 1);
283
284 return ref;
285 }
286
287 /******************************************************************************
288 * OleAdviseHolderImpl_Release
289 */
290 static ULONG WINAPI OleAdviseHolderImpl_Release(
291 LPOLEADVISEHOLDER iface)
292 {
293 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
294 ULONG ref;
295 TRACE("(%p)->(ref=%d)\n", This, This->ref);
296 ref = InterlockedDecrement(&This->ref);
297
298 if (ref == 0) OleAdviseHolderImpl_Destructor(This);
299
300 return ref;
301 }
302
303 /******************************************************************************
304 * OleAdviseHolderImpl_Advise
305 */
306 static HRESULT WINAPI OleAdviseHolderImpl_Advise(
307 LPOLEADVISEHOLDER iface,
308 IAdviseSink* pAdvise,
309 DWORD* pdwConnection)
310 {
311 DWORD index;
312
313 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
314
315 TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection);
316
317 /*
318 * Sanity check
319 */
320 if (pdwConnection==NULL)
321 return E_POINTER;
322
323 *pdwConnection = 0;
324
325 /*
326 * Find a free spot in the array.
327 */
328 for (index = 0; index < This->maxSinks; index++)
329 {
330 if (This->arrayOfSinks[index]==NULL)
331 break;
332 }
333
334 /*
335 * If the array is full, we need to grow it.
336 */
337 if (index == This->maxSinks)
338 {
339 DWORD i;
340
341 This->maxSinks+=INITIAL_SINKS;
342
343 This->arrayOfSinks = HeapReAlloc(GetProcessHeap(),
344 0,
345 This->arrayOfSinks,
346 This->maxSinks*sizeof(IAdviseSink*));
347
348 for (i=index;i < This->maxSinks; i++)
349 This->arrayOfSinks[i]=0;
350 }
351
352 /*
353 * Store the new sink
354 */
355 This->arrayOfSinks[index] = pAdvise;
356
357 if (This->arrayOfSinks[index]!=NULL)
358 IAdviseSink_AddRef(This->arrayOfSinks[index]);
359
360 /*
361 * Return the index as the cookie.
362 * Since 0 is not a valid cookie, we will increment by
363 * 1 the index in the table.
364 */
365 *pdwConnection = index+1;
366
367 return S_OK;
368 }
369
370 /******************************************************************************
371 * OleAdviseHolderImpl_Unadvise
372 */
373 static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(
374 LPOLEADVISEHOLDER iface,
375 DWORD dwConnection)
376 {
377 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
378
379 TRACE("(%p)->(%u)\n", This, dwConnection);
380
381 /*
382 * So we don't return 0 as a cookie, the index was
383 * incremented by 1 in OleAdviseHolderImpl_Advise
384 * we have to compensate.
385 */
386 dwConnection--;
387
388 /*
389 * Check for invalid cookies.
390 */
391 if (dwConnection >= This->maxSinks)
392 return OLE_E_NOCONNECTION;
393
394 if (This->arrayOfSinks[dwConnection] == NULL)
395 return OLE_E_NOCONNECTION;
396
397 /*
398 * Release the sink and mark the spot in the list as free.
399 */
400 IAdviseSink_Release(This->arrayOfSinks[dwConnection]);
401 This->arrayOfSinks[dwConnection] = NULL;
402
403 return S_OK;
404 }
405
406 /******************************************************************************
407 * OleAdviseHolderImpl_EnumAdvise
408 */
409 static HRESULT WINAPI
410 OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise)
411 {
412 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
413
414 TRACE("(%p)->(%p)\n", This, ppenumAdvise);
415
416 *ppenumAdvise = NULL;
417
418 return EnumOleSTATDATA_Construct(This, 0, ppenumAdvise);
419 }
420
421 /******************************************************************************
422 * OleAdviseHolderImpl_SendOnRename
423 */
424 static HRESULT WINAPI
425 OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk)
426 {
427 IEnumSTATDATA *pEnum;
428 HRESULT hr;
429
430 TRACE("(%p)->(%p)\n", iface, pmk);
431
432 hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
433 if (SUCCEEDED(hr))
434 {
435 STATDATA statdata;
436 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
437 {
438 IAdviseSink_OnRename(statdata.pAdvSink, pmk);
439
440 IAdviseSink_Release(statdata.pAdvSink);
441 }
442 IEnumSTATDATA_Release(pEnum);
443 }
444
445 return hr;
446 }
447
448 /******************************************************************************
449 * OleAdviseHolderImpl_SendOnSave
450 */
451 static HRESULT WINAPI
452 OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface)
453 {
454 IEnumSTATDATA *pEnum;
455 HRESULT hr;
456
457 TRACE("(%p)->()\n", iface);
458
459 hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
460 if (SUCCEEDED(hr))
461 {
462 STATDATA statdata;
463 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
464 {
465 IAdviseSink_OnSave(statdata.pAdvSink);
466
467 IAdviseSink_Release(statdata.pAdvSink);
468 }
469 IEnumSTATDATA_Release(pEnum);
470 }
471
472 return hr;
473 }
474
475 /******************************************************************************
476 * OleAdviseHolderImpl_SendOnClose
477 */
478 static HRESULT WINAPI
479 OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface)
480 {
481 IEnumSTATDATA *pEnum;
482 HRESULT hr;
483
484 TRACE("(%p)->()\n", iface);
485
486 hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
487 if (SUCCEEDED(hr))
488 {
489 STATDATA statdata;
490 while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
491 {
492 IAdviseSink_OnClose(statdata.pAdvSink);
493
494 IAdviseSink_Release(statdata.pAdvSink);
495 }
496 IEnumSTATDATA_Release(pEnum);
497 }
498
499 return hr;
500 }
501
502 /**************************************************************************
503 * OleAdviseHolderImpl_VTable
504 */
505 static const IOleAdviseHolderVtbl oahvt =
506 {
507 OleAdviseHolderImpl_QueryInterface,
508 OleAdviseHolderImpl_AddRef,
509 OleAdviseHolderImpl_Release,
510 OleAdviseHolderImpl_Advise,
511 OleAdviseHolderImpl_Unadvise,
512 OleAdviseHolderImpl_EnumAdvise,
513 OleAdviseHolderImpl_SendOnRename,
514 OleAdviseHolderImpl_SendOnSave,
515 OleAdviseHolderImpl_SendOnClose
516 };
517
518 /**************************************************************************
519 * OleAdviseHolderImpl_Constructor
520 */
521
522 static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor(void)
523 {
524 OleAdviseHolderImpl* lpoah;
525 DWORD index;
526
527 lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl));
528
529 lpoah->lpVtbl = &oahvt;
530 lpoah->ref = 1;
531 lpoah->maxSinks = INITIAL_SINKS;
532 lpoah->arrayOfSinks = HeapAlloc(GetProcessHeap(),
533 0,
534 lpoah->maxSinks * sizeof(IAdviseSink*));
535
536 for (index = 0; index < lpoah->maxSinks; index++)
537 lpoah->arrayOfSinks[index]=0;
538
539 TRACE("returning %p\n", lpoah);
540 return (LPOLEADVISEHOLDER)lpoah;
541 }
542
543 /**************************************************************************
544 * DataAdviseHolder Implementation
545 */
546 typedef struct DataAdviseConnection {
547 IAdviseSink *sink;
548 FORMATETC fmat;
549 DWORD advf;
550 DWORD remote_connection;
551 } DataAdviseConnection;
552
553 typedef struct DataAdviseHolder
554 {
555 const IDataAdviseHolderVtbl *lpVtbl;
556
557 LONG ref;
558 DWORD maxCons;
559 DataAdviseConnection* Connections;
560 IDataObject* delegate;
561 } DataAdviseHolder;
562
563 /* this connection has also has been advised to the delegate data object */
564 #define WINE_ADVF_REMOTE 0x80000000
565
566 /******************************************************************************
567 * DataAdviseHolder_Destructor
568 */
569 static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
570 {
571 DWORD index;
572 TRACE("%p\n", ptrToDestroy);
573
574 for (index = 0; index < ptrToDestroy->maxCons; index++)
575 {
576 if (ptrToDestroy->Connections[index].sink != NULL)
577 {
578 if (ptrToDestroy->delegate &&
579 (ptrToDestroy->Connections[index].advf & WINE_ADVF_REMOTE))
580 IDataObject_DUnadvise(ptrToDestroy->delegate,
581 ptrToDestroy->Connections[index].remote_connection);
582
583 IAdviseSink_Release(ptrToDestroy->Connections[index].sink);
584 ptrToDestroy->Connections[index].sink = NULL;
585 }
586 }
587
588 HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections);
589 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
590 }
591
592 /************************************************************************
593 * DataAdviseHolder_QueryInterface (IUnknown)
594 *
595 * See Windows documentation for more details on IUnknown methods.
596 */
597 static HRESULT WINAPI DataAdviseHolder_QueryInterface(
598 IDataAdviseHolder* iface,
599 REFIID riid,
600 void** ppvObject)
601 {
602 DataAdviseHolder *This = (DataAdviseHolder *)iface;
603 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
604 /*
605 * Perform a sanity check on the parameters.
606 */
607 if ( (This==0) || (ppvObject==0) )
608 return E_INVALIDARG;
609
610 /*
611 * Initialize the return parameter.
612 */
613 *ppvObject = 0;
614
615 /*
616 * Compare the riid with the interface IDs implemented by this object.
617 */
618 if ( IsEqualIID(&IID_IUnknown, riid) ||
619 IsEqualIID(&IID_IDataAdviseHolder, riid) )
620 {
621 *ppvObject = iface;
622 }
623
624 /*
625 * Check that we obtained an interface.
626 */
627 if ((*ppvObject)==0)
628 {
629 return E_NOINTERFACE;
630 }
631
632 /*
633 * Query Interface always increases the reference count by one when it is
634 * successful.
635 */
636 IUnknown_AddRef((IUnknown*)*ppvObject);
637
638 return S_OK;
639 }
640
641 /************************************************************************
642 * DataAdviseHolder_AddRef (IUnknown)
643 *
644 * See Windows documentation for more details on IUnknown methods.
645 */
646 static ULONG WINAPI DataAdviseHolder_AddRef(
647 IDataAdviseHolder* iface)
648 {
649 DataAdviseHolder *This = (DataAdviseHolder *)iface;
650 TRACE("(%p) (ref=%d)\n", This, This->ref);
651 return InterlockedIncrement(&This->ref);
652 }
653
654 /************************************************************************
655 * DataAdviseHolder_Release (IUnknown)
656 *
657 * See Windows documentation for more details on IUnknown methods.
658 */
659 static ULONG WINAPI DataAdviseHolder_Release(
660 IDataAdviseHolder* iface)
661 {
662 DataAdviseHolder *This = (DataAdviseHolder *)iface;
663 ULONG ref;
664 TRACE("(%p) (ref=%d)\n", This, This->ref);
665
666 /*
667 * Decrease the reference count on this object.
668 */
669 ref = InterlockedDecrement(&This->ref);
670
671 /*
672 * If the reference count goes down to 0, perform suicide.
673 */
674 if (ref==0) DataAdviseHolder_Destructor(This);
675
676 return ref;
677 }
678
679 /************************************************************************
680 * DataAdviseHolder_Advise
681 *
682 */
683 static HRESULT WINAPI DataAdviseHolder_Advise(
684 IDataAdviseHolder* iface,
685 IDataObject* pDataObject,
686 FORMATETC* pFetc,
687 DWORD advf,
688 IAdviseSink* pAdvise,
689 DWORD* pdwConnection)
690 {
691 DWORD index;
692
693 DataAdviseHolder *This = (DataAdviseHolder *)iface;
694
695 TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf,
696 pAdvise, pdwConnection);
697 /*
698 * Sanity check
699 */
700 if (pdwConnection==NULL)
701 return E_POINTER;
702
703 *pdwConnection = 0;
704
705 /*
706 * Find a free spot in the array.
707 */
708 for (index = 0; index < This->maxCons; index++)
709 {
710 if (This->Connections[index].sink == NULL)
711 break;
712 }
713
714 /*
715 * If the array is full, we need to grow it.
716 */
717 if (index == This->maxCons)
718 {
719 This->maxCons+=INITIAL_SINKS;
720 This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
721 This->Connections,
722 This->maxCons*sizeof(DataAdviseConnection));
723 }
724 /*
725 * Store the new sink
726 */
727 This->Connections[index].sink = pAdvise;
728 This->Connections[index].advf = advf & ~WINE_ADVF_REMOTE;
729 This->Connections[index].fmat = *pFetc;
730 if (pFetc->ptd)
731 {
732 This->Connections[index].fmat.ptd = CoTaskMemAlloc(pFetc->ptd->tdSize);
733 if (!This->Connections[index].fmat.ptd)
734 {
735 IDataAdviseHolder_Unadvise(iface, index + 1);
736 return E_OUTOFMEMORY;
737 }
738 memcpy(This->Connections[index].fmat.ptd, pFetc->ptd, pFetc->ptd->tdSize);
739 }
740
741 if (This->Connections[index].sink != NULL) {
742 IAdviseSink_AddRef(This->Connections[index].sink);
743
744 /* if we are already connected advise the remote object */
745 if (This->delegate)
746 {
747 HRESULT hr;
748
749 hr = IDataObject_DAdvise(This->delegate, &This->Connections[index].fmat,
750 This->Connections[index].advf,
751 This->Connections[index].sink,
752 &This->Connections[index].remote_connection);
753 if (FAILED(hr))
754 {
755 IDataAdviseHolder_Unadvise(iface, index + 1);
756 return hr;
757 }
758 This->Connections[index].advf |= WINE_ADVF_REMOTE;
759 }
760 else if(advf & ADVF_PRIMEFIRST)
761 /* only do this if we have no delegate, since in the above case the
762 * delegate will do the priming for us */
763 IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
764 }
765 /*
766 * Return the index as the cookie.
767 * Since 0 is not a valid cookie, we will increment by
768 * 1 the index in the table.
769 */
770 *pdwConnection = index+1;
771
772 return S_OK;
773 }
774
775 /******************************************************************************
776 * DataAdviseHolder_Unadvise
777 */
778 static HRESULT WINAPI DataAdviseHolder_Unadvise(
779 IDataAdviseHolder* iface,
780 DWORD dwConnection)
781 {
782 DataAdviseHolder *This = (DataAdviseHolder *)iface;
783
784 TRACE("(%p)->(%u)\n", This, dwConnection);
785
786 /*
787 * So we don't return 0 as a cookie, the index was
788 * incremented by 1 in OleAdviseHolderImpl_Advise
789 * we have to compensate.
790 */
791 dwConnection--;
792
793 /*
794 * Check for invalid cookies.
795 */
796 if (dwConnection >= This->maxCons)
797 return OLE_E_NOCONNECTION;
798
799 if (This->Connections[dwConnection].sink == NULL)
800 return OLE_E_NOCONNECTION;
801
802 if (This->delegate && This->Connections[dwConnection].advf & WINE_ADVF_REMOTE)
803 IDataObject_DUnadvise(This->delegate,
804 This->Connections[dwConnection].remote_connection);
805
806 /*
807 * Release the sink and mark the spot in the list as free.
808 */
809 IAdviseSink_Release(This->Connections[dwConnection].sink);
810 memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection));
811
812 return S_OK;
813 }
814
815 static HRESULT WINAPI DataAdviseHolder_EnumAdvise(
816 IDataAdviseHolder* iface,
817 IEnumSTATDATA** ppenumAdvise)
818 {
819 DataAdviseHolder *This = (DataAdviseHolder *)iface;
820
821 FIXME("(%p)->(%p)\n", This, ppenumAdvise);
822 return E_NOTIMPL;
823 }
824
825 /******************************************************************************
826 * DataAdviseHolder_SendOnDataChange
827 */
828 static HRESULT WINAPI DataAdviseHolder_SendOnDataChange(
829 IDataAdviseHolder* iface,
830 IDataObject* pDataObject,
831 DWORD dwReserved,
832 DWORD advf)
833 {
834 DataAdviseHolder *This = (DataAdviseHolder *)iface;
835 DWORD index;
836 STGMEDIUM stg;
837 HRESULT res;
838
839 TRACE("(%p)->(%p,%08x,%08x)\n", This, pDataObject, dwReserved, advf);
840
841 for(index = 0; index < This->maxCons; index++) {
842 if(This->Connections[index].sink != NULL) {
843 memset(&stg, 0, sizeof(stg));
844 if(!(This->Connections[index].advf & ADVF_NODATA)) {
845 TRACE("Calling IDataObject_GetData\n");
846 res = IDataObject_GetData(pDataObject,
847 &(This->Connections[index].fmat),
848 &stg);
849 TRACE("returns %08x\n", res);
850 }
851 TRACE("Calling IAdviseSink_OnDataChange\n");
852 IAdviseSink_OnDataChange(This->Connections[index].sink,
853 &(This->Connections[index].fmat),
854 &stg);
855 TRACE("Done IAdviseSink_OnDataChange\n");
856 if(This->Connections[index].advf & ADVF_ONLYONCE) {
857 TRACE("Removing connection\n");
858 DataAdviseHolder_Unadvise(iface, index+1);
859 }
860 }
861 }
862 return S_OK;
863 }
864
865 /**************************************************************************
866 * DataAdviseHolderImpl_VTable
867 */
868 static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
869 {
870 DataAdviseHolder_QueryInterface,
871 DataAdviseHolder_AddRef,
872 DataAdviseHolder_Release,
873 DataAdviseHolder_Advise,
874 DataAdviseHolder_Unadvise,
875 DataAdviseHolder_EnumAdvise,
876 DataAdviseHolder_SendOnDataChange
877 };
878
879 HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate)
880 {
881 DataAdviseHolder *This = (DataAdviseHolder *)iface;
882 DWORD index;
883 HRESULT hr = S_OK;
884
885 for(index = 0; index < This->maxCons; index++)
886 {
887 if(This->Connections[index].sink != NULL)
888 {
889 hr = IDataObject_DAdvise(pDelegate, &This->Connections[index].fmat,
890 This->Connections[index].advf,
891 This->Connections[index].sink,
892 &This->Connections[index].remote_connection);
893 if (FAILED(hr)) break;
894 This->Connections[index].advf |= WINE_ADVF_REMOTE;
895 }
896 }
897 This->delegate = pDelegate;
898 return hr;
899 }
900
901 void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface)
902 {
903 DataAdviseHolder *This = (DataAdviseHolder *)iface;
904 DWORD index;
905
906 for(index = 0; index < This->maxCons; index++)
907 {
908 if((This->Connections[index].sink != NULL) &&
909 (This->Connections[index].advf & WINE_ADVF_REMOTE))
910 {
911 IDataObject_DUnadvise(This->delegate,
912 This->Connections[index].remote_connection);
913 This->Connections[index].advf &= ~WINE_ADVF_REMOTE;
914 }
915 }
916 This->delegate = NULL;
917 }
918
919 /******************************************************************************
920 * DataAdviseHolder_Constructor
921 */
922 static IDataAdviseHolder* DataAdviseHolder_Constructor(void)
923 {
924 DataAdviseHolder* newHolder;
925
926 newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder));
927
928 newHolder->lpVtbl = &DataAdviseHolderImpl_VTable;
929 newHolder->ref = 1;
930 newHolder->maxCons = INITIAL_SINKS;
931 newHolder->Connections = HeapAlloc(GetProcessHeap(),
932 HEAP_ZERO_MEMORY,
933 newHolder->maxCons *
934 sizeof(DataAdviseConnection));
935 newHolder->delegate = NULL;
936
937 TRACE("returning %p\n", newHolder);
938 return (IDataAdviseHolder*)newHolder;
939 }
940
941 /***********************************************************************
942 * API functions
943 */
944
945 /***********************************************************************
946 * CreateOleAdviseHolder [OLE32.@]
947 */
948 HRESULT WINAPI CreateOleAdviseHolder(
949 LPOLEADVISEHOLDER *ppOAHolder)
950 {
951 TRACE("(%p)\n", ppOAHolder);
952
953 /*
954 * Sanity check,
955 */
956 if (ppOAHolder==NULL)
957 return E_POINTER;
958
959 *ppOAHolder = OleAdviseHolderImpl_Constructor ();
960
961 if (*ppOAHolder != NULL)
962 return S_OK;
963
964 return E_OUTOFMEMORY;
965 }
966
967 /******************************************************************************
968 * CreateDataAdviseHolder [OLE32.@]
969 */
970 HRESULT WINAPI CreateDataAdviseHolder(
971 LPDATAADVISEHOLDER* ppDAHolder)
972 {
973 TRACE("(%p)\n", ppDAHolder);
974
975 /*
976 * Sanity check,
977 */
978 if (ppDAHolder==NULL)
979 return E_POINTER;
980
981 *ppDAHolder = DataAdviseHolder_Constructor();
982
983 if (*ppDAHolder != NULL)
984 return S_OK;
985
986 return E_OUTOFMEMORY;
987 }