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