Fixed some warnings.
[wine] / dlls / oleaut32 / connpt.c
1 /*
2  * Implementation of a generic ConnectionPoint object.
3  *
4  * Copyright 2000 Huw D M Davies for CodeWeavers
5  *
6  * See one exported function here is CreateConnectionPoint, see
7  * comments just above that function for information.
8  */
9
10 #include <assert.h>
11 #include "winerror.h"
12 #include "winbase.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "ole2.h"
16 #include "olectl.h"
17 #include "wine/obj_base.h"
18 #include "wine/obj_connection.h"
19 #include "connpt.h"
20
21 #include "debugtools.h"
22
23 DEFAULT_DEBUG_CHANNEL(ole);
24
25 #define MAXSINKS 10
26
27 /************************************************************************
28  * Implementation of IConnectionPoint
29  */
30 typedef struct ConnectionPointImpl {
31
32   ICOM_VTABLE(IConnectionPoint)       *lpvtbl;
33
34   /* IUnknown of our main object*/
35   IUnknown *Obj;
36
37   /* Reference count */
38   DWORD ref;
39
40   /* IID of sink interface */
41   IID iid;
42
43   /* Array of sink IUnknowns */
44   IUnknown **sinks;
45   DWORD maxSinks;
46
47   DWORD nSinks;
48 } ConnectionPointImpl;
49
50 static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable;
51
52
53 /************************************************************************
54  * Implementation of IEnumConnections
55  */
56 typedef struct EnumConnectionsImpl {
57
58   ICOM_VTABLE(IEnumConnections)       *lpvtbl;
59
60   DWORD ref;
61
62   /* IUnknown of ConnectionPoint, used for ref counting */
63   IUnknown *pUnk;
64
65   /* Connection Data */
66   CONNECTDATA *pCD;
67   DWORD nConns;
68   
69   /* Next connection to enumerate from */
70   DWORD nCur;
71
72 } EnumConnectionsImpl;
73
74 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
75                                                           DWORD nSinks,
76                                                           CONNECTDATA *pCD);
77
78
79 /************************************************************************
80  * ConnectionPointImpl_Construct
81  */
82 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
83                                                           REFIID riid)
84 {
85   ConnectionPointImpl *Obj;
86
87   Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
88   Obj->lpvtbl = &ConnectionPointImpl_VTable;
89   Obj->Obj = pUnk;
90   Obj->ref = 1;
91   Obj->iid =  *riid;
92   Obj->maxSinks = MAXSINKS;
93   Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
94                          sizeof(IUnknown*) * MAXSINKS);
95   Obj->nSinks = 0;
96   return Obj;
97 }
98
99 /************************************************************************
100  * ConnectionPointImpl_Destroy
101  */
102 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
103 {
104   DWORD i;
105   for(i = 0; i < Obj->maxSinks; i++) {
106     if(Obj->sinks[i]) {
107       IUnknown_Release(Obj->sinks[i]);
108       Obj->sinks[i] = NULL;
109     }
110   }
111   HeapFree(GetProcessHeap(), 0, Obj->sinks);
112   HeapFree(GetProcessHeap(), 0, Obj);
113   return;
114 }
115
116 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
117 /************************************************************************
118  * ConnectionPointImpl_QueryInterface (IUnknown)
119  *
120  * See Windows documentation for more details on IUnknown methods.
121  */
122 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
123   IConnectionPoint*  iface,
124   REFIID  riid,
125   void**  ppvObject)
126 {
127   ICOM_THIS(ConnectionPointImpl, iface);
128   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
129
130   /*
131    * Perform a sanity check on the parameters.
132    */
133   if ( (This==0) || (ppvObject==0) )
134     return E_INVALIDARG;
135   
136   /*
137    * Initialize the return parameter.
138    */
139   *ppvObject = 0;
140   
141   /*
142    * Compare the riid with the interface IDs implemented by this object.
143    */
144   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
145   {
146     *ppvObject = (IConnectionPoint*)This;
147   }
148   else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0) 
149   {
150     *ppvObject = (IConnectionPoint*)This;
151   }
152   
153   /*
154    * Check that we obtained an interface.
155    */
156   if ((*ppvObject)==0)
157   {
158     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
159     return E_NOINTERFACE;
160   }
161   
162   /*
163    * Query Interface always increases the reference count by one when it is
164    * successful
165    */
166   ConnectionPointImpl_AddRef((IConnectionPoint*)This);
167
168   return S_OK;;
169 }
170
171
172 /************************************************************************
173  * ConnectionPointImpl_AddRef (IUnknown)
174  *
175  * See Windows documentation for more details on IUnknown methods.
176  */
177 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
178 {
179   ICOM_THIS(ConnectionPointImpl, iface);
180   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
181   This->ref++;
182
183   return This->ref;
184 }
185         
186 /************************************************************************
187  * ConnectionPointImpl_Release (IUnknown)
188  *
189  * See Windows documentation for more details on IUnknown methods.
190  */
191 static ULONG WINAPI ConnectionPointImpl_Release( 
192       IConnectionPoint* iface)
193 {
194   ICOM_THIS(ConnectionPointImpl, iface);
195   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
196
197   /*
198    * Decrease the reference count on this object.
199    */
200   This->ref--;
201
202   /*
203    * If the reference count goes down to 0, perform suicide.
204    */
205   if (This->ref==0)
206   {
207     ConnectionPointImpl_Destroy(This);
208
209     return 0;
210   }
211   
212   return This->ref;
213 }
214
215 /************************************************************************
216  * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
217  *
218  */
219 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
220                                                IConnectionPoint *iface,
221                                                IID              *piid)
222 {
223   ICOM_THIS(ConnectionPointImpl, iface);
224   TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
225   *piid = This->iid;
226   return S_OK;
227 }
228
229 /************************************************************************
230  * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
231  *
232  */
233 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
234                                       IConnectionPoint           *iface,
235                                       IConnectionPointContainer  **ppCPC)
236 {
237   ICOM_THIS(ConnectionPointImpl, iface);
238   TRACE("(%p)->(%p)\n", This, ppCPC);
239
240   return IUnknown_QueryInterface(This->Obj,
241                                  &IID_IConnectionPointContainer,
242                                  (LPVOID)ppCPC);
243 }
244
245 /************************************************************************
246  * ConnectionPointImpl_Advise (IConnectionPoint)
247  *
248  */
249 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
250                                                  IUnknown *lpUnk,
251                                                  DWORD *pdwCookie)
252 {
253   DWORD i;
254   ICOM_THIS(ConnectionPointImpl, iface);
255   IUnknown *lpSink;
256   TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
257
258   *pdwCookie = 0;
259   if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
260     return CONNECT_E_CANNOTCONNECT;
261
262   for(i = 0; i < This->maxSinks; i++) {
263     if(This->sinks[i] == NULL)
264       break;
265   }
266   if(i == This->maxSinks) {
267     This->maxSinks += MAXSINKS;
268     This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
269                               This->maxSinks * sizeof(IUnknown *));
270   }
271   This->sinks[i] = lpSink;
272   This->nSinks++;
273   *pdwCookie = i + 1;
274   return S_OK;
275 }
276
277
278 /************************************************************************
279  * ConnectionPointImpl_Unadvise (IConnectionPoint)
280  *
281  */
282 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
283                                                    DWORD dwCookie)
284 {
285   ICOM_THIS(ConnectionPointImpl, iface);
286   TRACE("(%p)->(%ld)\n", This, dwCookie);
287
288   if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
289
290   if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
291
292   IUnknown_Release(This->sinks[dwCookie-1]);
293   This->sinks[dwCookie-1] = NULL;
294   This->nSinks--;
295   return S_OK;
296 }
297
298 /************************************************************************
299  * ConnectionPointImpl_EnumConnections (IConnectionPoint)
300  *
301  */
302 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
303                                                     IConnectionPoint *iface,
304                                                     LPENUMCONNECTIONS *ppEnum)
305
306   ICOM_THIS(ConnectionPointImpl, iface);
307   CONNECTDATA *pCD;
308   DWORD i, nextslot;
309   EnumConnectionsImpl *EnumObj;
310   HRESULT hr;
311
312   TRACE("(%p)->(%p)\n", This, ppEnum);
313   
314   *ppEnum = NULL;
315
316   if(This->nSinks == 0) return OLE_E_NOCONNECTION;
317
318   pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
319
320   for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
321     if(This->sinks[i] != NULL) {
322       pCD[nextslot].pUnk = This->sinks[i];
323       pCD[nextslot].dwCookie = i + 1;
324       nextslot++;
325     }
326   }
327   assert(nextslot == This->nSinks);
328
329   /* Bump the ref count of this object up by one.  It gets Released in
330      IEnumConnections_Release */
331   IUnknown_AddRef((IUnknown*)This);
332
333   EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
334   hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj,
335                                   &IID_IEnumConnections, (LPVOID)ppEnum);
336   IEnumConnections_Release((IEnumConnections*)EnumObj);
337
338   HeapFree(GetProcessHeap(), 0, pCD);
339   return hr;
340 }
341
342 static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable =
343 {
344   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
345   ConnectionPointImpl_QueryInterface,
346   ConnectionPointImpl_AddRef,
347   ConnectionPointImpl_Release,
348   ConnectionPointImpl_GetConnectionInterface,
349   ConnectionPointImpl_GetConnectionPointContainer,
350   ConnectionPointImpl_Advise,
351   ConnectionPointImpl_Unadvise,
352   ConnectionPointImpl_EnumConnections
353 };
354
355
356 static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable;
357 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
358
359 /************************************************************************
360  * EnumConnectionsImpl_Construct
361  */
362 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
363                                                           DWORD nSinks,
364                                                           CONNECTDATA *pCD)
365 {
366   EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
367   DWORD i;
368
369   Obj->lpvtbl = &EnumConnectionsImpl_VTable;
370   Obj->ref = 1;
371   Obj->pUnk = pUnk;
372   Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
373   Obj->nConns = nSinks;
374   Obj->nCur = 0;
375
376   for(i = 0; i < nSinks; i++) {
377     Obj->pCD[i] = pCD[i];
378     IUnknown_AddRef(Obj->pCD[i].pUnk);
379   }
380   return Obj;
381 }
382
383 /************************************************************************
384  * EnumConnectionsImpl_Destroy
385  */
386 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
387 {
388   DWORD i;
389
390   for(i = 0; i < Obj->nConns; i++)
391     IUnknown_Release(Obj->pCD[i].pUnk);
392
393   HeapFree(GetProcessHeap(), 0, Obj->pCD);
394   HeapFree(GetProcessHeap(), 0, Obj);
395   return;
396 }
397
398 /************************************************************************
399  * EnumConnectionsImpl_QueryInterface (IUnknown)
400  *
401  * See Windows documentation for more details on IUnknown methods.
402  */
403 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
404   IEnumConnections*  iface,
405   REFIID  riid,
406   void**  ppvObject)
407 {
408   ICOM_THIS(ConnectionPointImpl, iface);
409   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
410
411   /*
412    * Perform a sanity check on the parameters.
413    */
414   if ( (This==0) || (ppvObject==0) )
415     return E_INVALIDARG;
416   
417   /*
418    * Initialize the return parameter.
419    */
420   *ppvObject = 0;
421   
422   /*
423    * Compare the riid with the interface IDs implemented by this object.
424    */
425   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
426   {
427     *ppvObject = (IEnumConnections*)This;
428   }
429   else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0) 
430   {
431     *ppvObject = (IEnumConnections*)This;
432   }
433   
434   /*
435    * Check that we obtained an interface.
436    */
437   if ((*ppvObject)==0)
438   {
439     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
440     return E_NOINTERFACE;
441   }
442   
443   /*
444    * Query Interface always increases the reference count by one when it is
445    * successful
446    */
447   EnumConnectionsImpl_AddRef((IEnumConnections*)This);
448
449   return S_OK;;
450 }
451
452
453 /************************************************************************
454  * EnumConnectionsImpl_AddRef (IUnknown)
455  *
456  * See Windows documentation for more details on IUnknown methods.
457  */
458 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
459 {
460   ICOM_THIS(EnumConnectionsImpl, iface);
461   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
462   This->ref++;
463   IUnknown_AddRef(This->pUnk);
464   return This->ref;
465 }
466         
467 /************************************************************************
468  * EnumConnectionsImpl_Release (IUnknown)
469  *
470  * See Windows documentation for more details on IUnknown methods.
471  */
472 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
473 {
474   ICOM_THIS(EnumConnectionsImpl, iface);
475   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
476
477   IUnknown_Release(This->pUnk);
478
479   /*
480    * Decrease the reference count on this object.
481    */
482   This->ref--;
483
484   /*
485    * If the reference count goes down to 0, perform suicide.
486    */
487   if (This->ref==0)
488   {
489     EnumConnectionsImpl_Destroy(This);
490
491     return 0;
492   }
493   
494   return This->ref;
495 }
496
497 /************************************************************************
498  * EnumConnectionsImpl_Next (IEnumConnections)
499  *
500  */
501 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
502                                                ULONG cConn, LPCONNECTDATA pCD,
503                                                ULONG *pEnum)
504 {
505   ICOM_THIS(EnumConnectionsImpl, iface);
506   DWORD nRet = 0;
507   TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum);
508
509   if(pEnum == NULL) {
510     if(cConn != 1)
511       return E_POINTER;
512   } else
513     *pEnum = 0;
514
515   if(This->nCur >= This->nConns)
516     return S_FALSE;
517
518   while(This->nCur < This->nConns && cConn) {
519     *pCD++ = This->pCD[This->nCur];
520     IUnknown_AddRef(This->pCD[This->nCur].pUnk);
521     This->nCur++;
522     cConn--;
523     nRet++;
524   }
525
526   if(pEnum)
527     *pEnum = nRet;
528
529   return S_OK;
530 }
531
532
533 /************************************************************************
534  * EnumConnectionsImpl_Skip (IEnumConnections)
535  *
536  */
537 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
538                                                ULONG cSkip)
539 {
540   ICOM_THIS(EnumConnectionsImpl, iface);
541   TRACE("(%p)->(%ld)\n", This, cSkip);
542
543   if(This->nCur + cSkip >= This->nConns)
544     return S_FALSE;
545
546   This->nCur += cSkip;
547
548   return S_OK;
549 }
550
551
552 /************************************************************************
553  * EnumConnectionsImpl_Reset (IEnumConnections)
554  *
555  */
556 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
557 {
558   ICOM_THIS(EnumConnectionsImpl, iface);
559   TRACE("(%p)\n", This);
560
561   This->nCur = 0;
562
563   return S_OK;
564 }
565
566
567 /************************************************************************
568  * EnumConnectionsImpl_Clone (IEnumConnections)
569  *
570  */
571 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
572                                                 LPENUMCONNECTIONS *ppEnum)
573 {
574   ICOM_THIS(EnumConnectionsImpl, iface);
575   EnumConnectionsImpl *newObj;
576   TRACE("(%p)->(%p)\n", This, ppEnum);
577   
578   newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
579   newObj->nCur = This->nCur;
580   *ppEnum = (LPENUMCONNECTIONS)newObj;
581   IUnknown_AddRef(This->pUnk);
582   return S_OK;
583 }
584   
585 static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable =
586 {
587   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
588   EnumConnectionsImpl_QueryInterface,
589   EnumConnectionsImpl_AddRef,
590   EnumConnectionsImpl_Release,
591   EnumConnectionsImpl_Next,
592   EnumConnectionsImpl_Skip,
593   EnumConnectionsImpl_Reset,
594   EnumConnectionsImpl_Clone
595 };
596
597 /************************************************************************
598  *
599  *  The exported function to create the connection point.
600  *  NB not a windows API
601  *
602  * PARAMS
603  * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
604  *           Needed to access IConnectionPointContainer.
605  *
606  * riid [in] IID of sink interface that this ConnectionPoint manages
607  *
608  * pCP [out] returns IConnectionPoint
609  *
610  */
611 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
612                               IConnectionPoint **pCP)
613 {
614   ConnectionPointImpl *Obj;
615   HRESULT hr;
616
617   Obj = ConnectionPointImpl_Construct(pUnk, riid);
618   if(!Obj) return E_OUTOFMEMORY;
619
620   hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj, 
621                                        &IID_IConnectionPoint, (LPVOID)pCP);
622   IConnectionPoint_Release((IConnectionPoint *)Obj);
623   return hr;
624 }