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