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