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