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