Sync to Wine-20050725:
[reactos.git] / reactos / lib / ole32 / oleobj.c
1 /*
2 * OLE2 COM objects
3 *
4 * Copyright 1998 Eric Kohl
5 * Copyright 1999 Francis Beaudet
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #define COBJMACROS
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "wine/debug.h"
33 #include "ole2.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36
37 #define INITIAL_SINKS 10
38
39 /**************************************************************************
40 * OleAdviseHolderImpl Implementation
41 */
42 typedef struct OleAdviseHolderImpl
43 {
44 const IOleAdviseHolderVtbl *lpVtbl;
45
46 LONG ref;
47
48 DWORD maxSinks;
49 IAdviseSink** arrayOfSinks;
50
51 } OleAdviseHolderImpl;
52
53 /**************************************************************************
54 * OleAdviseHolderImpl_Destructor
55 */
56 static void OleAdviseHolderImpl_Destructor(
57 OleAdviseHolderImpl* ptrToDestroy)
58 {
59 DWORD index;
60 TRACE("%p\n", ptrToDestroy);
61
62 for (index = 0; index < ptrToDestroy->maxSinks; index++)
63 {
64 if (ptrToDestroy->arrayOfSinks[index]!=0)
65 {
66 IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]);
67 ptrToDestroy->arrayOfSinks[index] = NULL;
68 }
69 }
70
71 HeapFree(GetProcessHeap(),
72 0,
73 ptrToDestroy->arrayOfSinks);
74
75
76 HeapFree(GetProcessHeap(),
77 0,
78 ptrToDestroy);
79 }
80
81 /**************************************************************************
82 * OleAdviseHolderImpl_QueryInterface
83 */
84 static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(
85 LPOLEADVISEHOLDER iface,
86 REFIID riid,
87 LPVOID* ppvObj)
88 {
89 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
90 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObj);
91 /*
92 * Sanity check
93 */
94 if (ppvObj==NULL)
95 return E_POINTER;
96
97 *ppvObj = NULL;
98
99 if (IsEqualIID(riid, &IID_IUnknown))
100 {
101 /* IUnknown */
102 *ppvObj = This;
103 }
104 else if(IsEqualIID(riid, &IID_IOleAdviseHolder))
105 {
106 /* IOleAdviseHolder */
107 *ppvObj = (IOleAdviseHolder*) This;
108 }
109
110 if(*ppvObj == NULL)
111 return E_NOINTERFACE;
112
113 /*
114 * A successful QI always increments the reference count.
115 */
116 IUnknown_AddRef((IUnknown*)*ppvObj);
117
118 return S_OK;
119 }
120
121 /******************************************************************************
122 * OleAdviseHolderImpl_AddRef
123 */
124 static ULONG WINAPI OleAdviseHolderImpl_AddRef(
125 LPOLEADVISEHOLDER iface)
126 {
127 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
128 ULONG ref = InterlockedIncrement(&This->ref);
129
130 TRACE("(%p)->(ref=%ld)\n", This, ref - 1);
131
132 return ref;
133 }
134
135 /******************************************************************************
136 * OleAdviseHolderImpl_Release
137 */
138 static ULONG WINAPI OleAdviseHolderImpl_Release(
139 LPOLEADVISEHOLDER iface)
140 {
141 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
142 ULONG ref;
143 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
144 ref = InterlockedDecrement(&This->ref);
145
146 if (ref == 0) OleAdviseHolderImpl_Destructor(This);
147
148 return ref;
149 }
150
151 /******************************************************************************
152 * OleAdviseHolderImpl_Advise
153 */
154 static HRESULT WINAPI OleAdviseHolderImpl_Advise(
155 LPOLEADVISEHOLDER iface,
156 IAdviseSink* pAdvise,
157 DWORD* pdwConnection)
158 {
159 DWORD index;
160
161 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
162
163 TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection);
164
165 /*
166 * Sanity check
167 */
168 if (pdwConnection==NULL)
169 return E_POINTER;
170
171 *pdwConnection = 0;
172
173 /*
174 * Find a free spot in the array.
175 */
176 for (index = 0; index < This->maxSinks; index++)
177 {
178 if (This->arrayOfSinks[index]==NULL)
179 break;
180 }
181
182 /*
183 * If the array is full, we need to grow it.
184 */
185 if (index == This->maxSinks)
186 {
187 DWORD i;
188
189 This->maxSinks+=INITIAL_SINKS;
190
191 This->arrayOfSinks = HeapReAlloc(GetProcessHeap(),
192 0,
193 This->arrayOfSinks,
194 This->maxSinks*sizeof(IAdviseSink*));
195
196 for (i=index;i < This->maxSinks; i++)
197 This->arrayOfSinks[i]=0;
198 }
199
200 /*
201 * Store the new sink
202 */
203 This->arrayOfSinks[index] = pAdvise;
204
205 if (This->arrayOfSinks[index]!=NULL)
206 IAdviseSink_AddRef(This->arrayOfSinks[index]);
207
208 /*
209 * Return the index as the cookie.
210 * Since 0 is not a valid cookie, we will increment by
211 * 1 the index in the table.
212 */
213 *pdwConnection = index+1;
214
215 return S_OK;
216 }
217
218 /******************************************************************************
219 * OleAdviseHolderImpl_Unadvise
220 */
221 static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(
222 LPOLEADVISEHOLDER iface,
223 DWORD dwConnection)
224 {
225 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
226
227 TRACE("(%p)->(%lu)\n", This, dwConnection);
228
229 /*
230 * So we don't return 0 as a cookie, the index was
231 * incremented by 1 in OleAdviseHolderImpl_Advise
232 * we have to compensate.
233 */
234 dwConnection--;
235
236 /*
237 * Check for invalid cookies.
238 */
239 if (dwConnection >= This->maxSinks)
240 return OLE_E_NOCONNECTION;
241
242 if (This->arrayOfSinks[dwConnection] == NULL)
243 return OLE_E_NOCONNECTION;
244
245 /*
246 * Release the sink and mark the spot in the list as free.
247 */
248 IAdviseSink_Release(This->arrayOfSinks[dwConnection]);
249 This->arrayOfSinks[dwConnection] = NULL;
250
251 return S_OK;
252 }
253
254 /******************************************************************************
255 * OleAdviseHolderImpl_EnumAdvise
256 */
257 static HRESULT WINAPI
258 OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise)
259 {
260 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
261 FIXME("(%p)->(%p)\n", This, ppenumAdvise);
262
263 *ppenumAdvise = NULL;
264
265 return S_OK;
266 }
267
268 /******************************************************************************
269 * OleAdviseHolderImpl_SendOnRename
270 */
271 static HRESULT WINAPI
272 OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk)
273 {
274 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
275 FIXME("(%p)->(%p)\n", This, pmk);
276
277
278 return S_OK;
279 }
280
281 /******************************************************************************
282 * OleAdviseHolderImpl_SendOnSave
283 */
284 static HRESULT WINAPI
285 OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface)
286 {
287 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
288 FIXME("(%p)\n", This);
289
290 return S_OK;
291 }
292
293 /******************************************************************************
294 * OleAdviseHolderImpl_SendOnClose
295 */
296 static HRESULT WINAPI
297 OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface)
298 {
299 OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface;
300 FIXME("(%p)\n", This);
301
302
303 return S_OK;
304 }
305
306 /**************************************************************************
307 * OleAdviseHolderImpl_VTable
308 */
309 static const IOleAdviseHolderVtbl oahvt =
310 {
311 OleAdviseHolderImpl_QueryInterface,
312 OleAdviseHolderImpl_AddRef,
313 OleAdviseHolderImpl_Release,
314 OleAdviseHolderImpl_Advise,
315 OleAdviseHolderImpl_Unadvise,
316 OleAdviseHolderImpl_EnumAdvise,
317 OleAdviseHolderImpl_SendOnRename,
318 OleAdviseHolderImpl_SendOnSave,
319 OleAdviseHolderImpl_SendOnClose
320 };
321
322 /**************************************************************************
323 * OleAdviseHolderImpl_Constructor
324 */
325
326 static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor(void)
327 {
328 OleAdviseHolderImpl* lpoah;
329 DWORD index;
330
331 lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl));
332
333 lpoah->lpVtbl = &oahvt;
334 lpoah->ref = 1;
335 lpoah->maxSinks = INITIAL_SINKS;
336 lpoah->arrayOfSinks = HeapAlloc(GetProcessHeap(),
337 0,
338 lpoah->maxSinks * sizeof(IAdviseSink*));
339
340 for (index = 0; index < lpoah->maxSinks; index++)
341 lpoah->arrayOfSinks[index]=0;
342
343 TRACE("returning %p\n", lpoah);
344 return (LPOLEADVISEHOLDER)lpoah;
345 }
346
347 /**************************************************************************
348 * DataAdviseHolder Implementation
349 */
350 typedef struct DataAdviseConnection {
351 IAdviseSink *sink;
352 FORMATETC fmat;
353 DWORD advf;
354 } DataAdviseConnection;
355
356 typedef struct DataAdviseHolder
357 {
358 const IDataAdviseHolderVtbl *lpVtbl;
359
360 LONG ref;
361 DWORD maxCons;
362 DataAdviseConnection* Connections;
363 } DataAdviseHolder;
364
365 /******************************************************************************
366 * DataAdviseHolder_Destructor
367 */
368 static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
369 {
370 DWORD index;
371 TRACE("%p\n", ptrToDestroy);
372
373 for (index = 0; index < ptrToDestroy->maxCons; index++)
374 {
375 if (ptrToDestroy->Connections[index].sink != NULL)
376 {
377 IAdviseSink_Release(ptrToDestroy->Connections[index].sink);
378 ptrToDestroy->Connections[index].sink = NULL;
379 }
380 }
381
382 HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections);
383 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
384 }
385
386 /************************************************************************
387 * DataAdviseHolder_QueryInterface (IUnknown)
388 *
389 * See Windows documentation for more details on IUnknown methods.
390 */
391 static HRESULT WINAPI DataAdviseHolder_QueryInterface(
392 IDataAdviseHolder* iface,
393 REFIID riid,
394 void** ppvObject)
395 {
396 DataAdviseHolder *This = (DataAdviseHolder *)iface;
397 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
398 /*
399 * Perform a sanity check on the parameters.
400 */
401 if ( (This==0) || (ppvObject==0) )
402 return E_INVALIDARG;
403
404 /*
405 * Initialize the return parameter.
406 */
407 *ppvObject = 0;
408
409 /*
410 * Compare the riid with the interface IDs implemented by this object.
411 */
412 if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) ||
413 (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0) )
414 {
415 *ppvObject = iface;
416 }
417
418 /*
419 * Check that we obtained an interface.
420 */
421 if ((*ppvObject)==0)
422 {
423 return E_NOINTERFACE;
424 }
425
426 /*
427 * Query Interface always increases the reference count by one when it is
428 * successful.
429 */
430 IUnknown_AddRef((IUnknown*)*ppvObject);
431
432 return S_OK;
433 }
434
435 /************************************************************************
436 * DataAdviseHolder_AddRef (IUnknown)
437 *
438 * See Windows documentation for more details on IUnknown methods.
439 */
440 static ULONG WINAPI DataAdviseHolder_AddRef(
441 IDataAdviseHolder* iface)
442 {
443 DataAdviseHolder *This = (DataAdviseHolder *)iface;
444 TRACE("(%p) (ref=%ld)\n", This, This->ref);
445 return InterlockedIncrement(&This->ref);
446 }
447
448 /************************************************************************
449 * DataAdviseHolder_Release (IUnknown)
450 *
451 * See Windows documentation for more details on IUnknown methods.
452 */
453 static ULONG WINAPI DataAdviseHolder_Release(
454 IDataAdviseHolder* iface)
455 {
456 DataAdviseHolder *This = (DataAdviseHolder *)iface;
457 ULONG ref;
458 TRACE("(%p) (ref=%ld)\n", This, This->ref);
459
460 /*
461 * Decrease the reference count on this object.
462 */
463 ref = InterlockedDecrement(&This->ref);
464
465 /*
466 * If the reference count goes down to 0, perform suicide.
467 */
468 if (ref==0) DataAdviseHolder_Destructor(This);
469
470 return ref;
471 }
472
473 /************************************************************************
474 * DataAdviseHolder_Advise
475 *
476 */
477 static HRESULT WINAPI DataAdviseHolder_Advise(
478 IDataAdviseHolder* iface,
479 IDataObject* pDataObject,
480 FORMATETC* pFetc,
481 DWORD advf,
482 IAdviseSink* pAdvise,
483 DWORD* pdwConnection)
484 {
485 DWORD index;
486
487 DataAdviseHolder *This = (DataAdviseHolder *)iface;
488
489 TRACE("(%p)->(%p, %p, %08lx, %p, %p)\n", This, pDataObject, pFetc, advf,
490 pAdvise, pdwConnection);
491 /*
492 * Sanity check
493 */
494 if (pdwConnection==NULL)
495 return E_POINTER;
496
497 *pdwConnection = 0;
498
499 /*
500 * Find a free spot in the array.
501 */
502 for (index = 0; index < This->maxCons; index++)
503 {
504 if (This->Connections[index].sink == NULL)
505 break;
506 }
507
508 /*
509 * If the array is full, we need to grow it.
510 */
511 if (index == This->maxCons)
512 {
513 This->maxCons+=INITIAL_SINKS;
514 This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
515 This->Connections,
516 This->maxCons*sizeof(DataAdviseConnection));
517 }
518 /*
519 * Store the new sink
520 */
521 This->Connections[index].sink = pAdvise;
522 memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC));
523 This->Connections[index].advf = advf;
524
525 if (This->Connections[index].sink != NULL) {
526 IAdviseSink_AddRef(This->Connections[index].sink);
527 if(advf & ADVF_PRIMEFIRST) {
528 IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
529 }
530 }
531 /*
532 * Return the index as the cookie.
533 * Since 0 is not a valid cookie, we will increment by
534 * 1 the index in the table.
535 */
536 *pdwConnection = index+1;
537
538 return S_OK;
539 }
540
541 /******************************************************************************
542 * DataAdviseHolder_Unadvise
543 */
544 static HRESULT WINAPI DataAdviseHolder_Unadvise(
545 IDataAdviseHolder* iface,
546 DWORD dwConnection)
547 {
548 DataAdviseHolder *This = (DataAdviseHolder *)iface;
549
550 TRACE("(%p)->(%lu)\n", This, dwConnection);
551
552 /*
553 * So we don't return 0 as a cookie, the index was
554 * incremented by 1 in OleAdviseHolderImpl_Advise
555 * we have to compensate.
556 */
557 dwConnection--;
558
559 /*
560 * Check for invalid cookies.
561 */
562 if (dwConnection >= This->maxCons)
563 return OLE_E_NOCONNECTION;
564
565 if (This->Connections[dwConnection].sink == NULL)
566 return OLE_E_NOCONNECTION;
567
568 /*
569 * Release the sink and mark the spot in the list as free.
570 */
571 IAdviseSink_Release(This->Connections[dwConnection].sink);
572 memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection));
573 return S_OK;
574 }
575
576 static HRESULT WINAPI DataAdviseHolder_EnumAdvise(
577 IDataAdviseHolder* iface,
578 IEnumSTATDATA** ppenumAdvise)
579 {
580 DataAdviseHolder *This = (DataAdviseHolder *)iface;
581
582 FIXME("(%p)->(%p)\n", This, ppenumAdvise);
583 return E_NOTIMPL;
584 }
585
586 /******************************************************************************
587 * DataAdviseHolder_SendOnDataChange
588 */
589 static HRESULT WINAPI DataAdviseHolder_SendOnDataChange(
590 IDataAdviseHolder* iface,
591 IDataObject* pDataObject,
592 DWORD dwReserved,
593 DWORD advf)
594 {
595 DataAdviseHolder *This = (DataAdviseHolder *)iface;
596 DWORD index;
597 STGMEDIUM stg;
598 HRESULT res;
599
600 TRACE("(%p)->(%p,%08lx,%08lx)\n", This, pDataObject, dwReserved, advf);
601
602 for(index = 0; index < This->maxCons; index++) {
603 if(This->Connections[index].sink != NULL) {
604 if(!(This->Connections[index].advf & ADVF_NODATA)) {
605 TRACE("Calling IDataObject_GetData\n");
606 res = IDataObject_GetData(pDataObject,
607 &(This->Connections[index].fmat),
608 &stg);
609 TRACE("returns %08lx\n", res);
610 }
611 TRACE("Calling IAdviseSink_OnDataChange\n");
612 IAdviseSink_OnDataChange(This->Connections[index].sink,
613 &(This->Connections[index].fmat),
614 &stg);
615 TRACE("Done IAdviseSink_OnDataChange\n");
616 if(This->Connections[index].advf & ADVF_ONLYONCE) {
617 TRACE("Removing connection\n");
618 DataAdviseHolder_Unadvise(iface, index+1);
619 }
620 }
621 }
622 return S_OK;
623 }
624
625 /**************************************************************************
626 * DataAdviseHolderImpl_VTable
627 */
628 static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
629 {
630 DataAdviseHolder_QueryInterface,
631 DataAdviseHolder_AddRef,
632 DataAdviseHolder_Release,
633 DataAdviseHolder_Advise,
634 DataAdviseHolder_Unadvise,
635 DataAdviseHolder_EnumAdvise,
636 DataAdviseHolder_SendOnDataChange
637 };
638
639 /******************************************************************************
640 * DataAdviseHolder_Constructor
641 */
642 static IDataAdviseHolder* DataAdviseHolder_Constructor(void)
643 {
644 DataAdviseHolder* newHolder;
645
646 newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder));
647
648 newHolder->lpVtbl = &DataAdviseHolderImpl_VTable;
649 newHolder->ref = 1;
650 newHolder->maxCons = INITIAL_SINKS;
651 newHolder->Connections = HeapAlloc(GetProcessHeap(),
652 HEAP_ZERO_MEMORY,
653 newHolder->maxCons *
654 sizeof(DataAdviseConnection));
655
656 TRACE("returning %p\n", newHolder);
657 return (IDataAdviseHolder*)newHolder;
658 }
659
660 /***********************************************************************
661 * API functions
662 */
663
664 /***********************************************************************
665 * CreateOleAdviseHolder [OLE32.@]
666 */
667 HRESULT WINAPI CreateOleAdviseHolder(
668 LPOLEADVISEHOLDER *ppOAHolder)
669 {
670 TRACE("(%p)\n", ppOAHolder);
671
672 /*
673 * Sanity check,
674 */
675 if (ppOAHolder==NULL)
676 return E_POINTER;
677
678 *ppOAHolder = OleAdviseHolderImpl_Constructor ();
679
680 if (*ppOAHolder != NULL)
681 return S_OK;
682
683 return E_OUTOFMEMORY;
684 }
685
686 /******************************************************************************
687 * CreateDataAdviseHolder [OLE32.@]
688 */
689 HRESULT WINAPI CreateDataAdviseHolder(
690 LPDATAADVISEHOLDER* ppDAHolder)
691 {
692 TRACE("(%p)\n", ppDAHolder);
693
694 /*
695 * Sanity check,
696 */
697 if (ppDAHolder==NULL)
698 return E_POINTER;
699
700 *ppDAHolder = DataAdviseHolder_Constructor();
701
702 if (*ppDAHolder != NULL)
703 return S_OK;
704
705 return E_OUTOFMEMORY;
706 }