xref: /reactos/dll/win32/oleaut32/connpt.c (revision 60eea2d7)
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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   const IConnectionPointVtbl *lpvtbl;
52 
53   /* IUnknown of our main object*/
54   IUnknown *Obj;
55 
56   /* Reference count */
57   LONG 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 const IConnectionPointVtbl ConnectionPointImpl_VTable;
70 
71 
72 /************************************************************************
73  * Implementation of IEnumConnections
74  */
75 typedef struct EnumConnectionsImpl {
76 
77   const IEnumConnectionsVtbl *lpvtbl;
78 
79   LONG 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 (IsEqualIID(&IID_IUnknown, riid))
164     *ppvObject = This;
165   else if (IsEqualIID(&IID_IConnectionPoint, riid))
166     *ppvObject = This;
167 
168   /*
169    * Check that we obtained an interface.
170    */
171   if ((*ppvObject)==0)
172   {
173     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
174     return E_NOINTERFACE;
175   }
176 
177   /*
178    * Query Interface always increases the reference count by one when it is
179    * successful
180    */
181   ConnectionPointImpl_AddRef((IConnectionPoint*)This);
182 
183   return S_OK;
184 }
185 
186 
187 /************************************************************************
188  * ConnectionPointImpl_AddRef (IUnknown)
189  *
190  * See Windows documentation for more details on IUnknown methods.
191  */
192 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
193 {
194   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
195   ULONG refCount = InterlockedIncrement(&This->ref);
196 
197   TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
198 
199   return refCount;
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   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
211   ULONG refCount = InterlockedDecrement(&This->ref);
212 
213   TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
214 
215   /*
216    * If the reference count goes down to 0, perform suicide.
217    */
218   if (!refCount) ConnectionPointImpl_Destroy(This);
219 
220   return refCount;
221 }
222 
223 /************************************************************************
224  * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
225  *
226  */
227 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
228 					       IConnectionPoint *iface,
229 					       IID              *piid)
230 {
231   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
232   TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
233   *piid = This->iid;
234   return S_OK;
235 }
236 
237 /************************************************************************
238  * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
239  *
240  */
241 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
242 				      IConnectionPoint           *iface,
243 				      IConnectionPointContainer  **ppCPC)
244 {
245   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
246   TRACE("(%p)->(%p)\n", This, ppCPC);
247 
248   return IUnknown_QueryInterface(This->Obj,
249 				 &IID_IConnectionPointContainer,
250 				 (LPVOID)ppCPC);
251 }
252 
253 /************************************************************************
254  * ConnectionPointImpl_Advise (IConnectionPoint)
255  *
256  */
257 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
258 						 IUnknown *lpUnk,
259 						 DWORD *pdwCookie)
260 {
261   DWORD i;
262   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
263   IUnknown *lpSink;
264   TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
265 
266   *pdwCookie = 0;
267   if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
268     return CONNECT_E_CANNOTCONNECT;
269 
270   for(i = 0; i < This->maxSinks; i++) {
271     if(This->sinks[i] == NULL)
272       break;
273   }
274   if(i == This->maxSinks) {
275     This->maxSinks += MAXSINKS;
276     This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
277 			      This->maxSinks * sizeof(IUnknown *));
278   }
279   This->sinks[i] = lpSink;
280   This->nSinks++;
281   *pdwCookie = i + 1;
282   return S_OK;
283 }
284 
285 
286 /************************************************************************
287  * ConnectionPointImpl_Unadvise (IConnectionPoint)
288  *
289  */
290 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
291 						   DWORD dwCookie)
292 {
293   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
294   TRACE("(%p)->(%d)\n", This, dwCookie);
295 
296   if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
297 
298   if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
299 
300   IUnknown_Release(This->sinks[dwCookie-1]);
301   This->sinks[dwCookie-1] = NULL;
302   This->nSinks--;
303   return S_OK;
304 }
305 
306 /************************************************************************
307  * ConnectionPointImpl_EnumConnections (IConnectionPoint)
308  *
309  */
310 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
311 						    IConnectionPoint *iface,
312 						    LPENUMCONNECTIONS *ppEnum)
313 {
314   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
315   CONNECTDATA *pCD;
316   DWORD i, nextslot;
317   EnumConnectionsImpl *EnumObj;
318   HRESULT hr;
319 
320   TRACE("(%p)->(%p)\n", This, ppEnum);
321 
322   *ppEnum = NULL;
323 
324   if(This->nSinks == 0) return OLE_E_NOCONNECTION;
325 
326   pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
327 
328   for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
329     if(This->sinks[i] != NULL) {
330       pCD[nextslot].pUnk = This->sinks[i];
331       pCD[nextslot].dwCookie = i + 1;
332       nextslot++;
333     }
334   }
335   assert(nextslot == This->nSinks);
336 
337   /* Bump the ref count of this object up by one.  It gets Released in
338      IEnumConnections_Release */
339   IUnknown_AddRef((IUnknown*)This);
340 
341   EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
342   hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj,
343 				  &IID_IEnumConnections, (LPVOID)ppEnum);
344   IEnumConnections_Release((IEnumConnections*)EnumObj);
345 
346   HeapFree(GetProcessHeap(), 0, pCD);
347   return hr;
348 }
349 
350 static const IConnectionPointVtbl ConnectionPointImpl_VTable =
351 {
352   ConnectionPointImpl_QueryInterface,
353   ConnectionPointImpl_AddRef,
354   ConnectionPointImpl_Release,
355   ConnectionPointImpl_GetConnectionInterface,
356   ConnectionPointImpl_GetConnectionPointContainer,
357   ConnectionPointImpl_Advise,
358   ConnectionPointImpl_Unadvise,
359   ConnectionPointImpl_EnumConnections
360 };
361 
362 
363 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
364 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
365 
366 /************************************************************************
367  * EnumConnectionsImpl_Construct
368  */
369 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
370 							  DWORD nSinks,
371 							  CONNECTDATA *pCD)
372 {
373   EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
374   DWORD i;
375 
376   Obj->lpvtbl = &EnumConnectionsImpl_VTable;
377   Obj->ref = 1;
378   Obj->pUnk = pUnk;
379   Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
380   Obj->nConns = nSinks;
381   Obj->nCur = 0;
382 
383   for(i = 0; i < nSinks; i++) {
384     Obj->pCD[i] = pCD[i];
385     IUnknown_AddRef(Obj->pCD[i].pUnk);
386   }
387   return Obj;
388 }
389 
390 /************************************************************************
391  * EnumConnectionsImpl_Destroy
392  */
393 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
394 {
395   DWORD i;
396 
397   for(i = 0; i < Obj->nConns; i++)
398     IUnknown_Release(Obj->pCD[i].pUnk);
399 
400   HeapFree(GetProcessHeap(), 0, Obj->pCD);
401   HeapFree(GetProcessHeap(), 0, Obj);
402   return;
403 }
404 
405 /************************************************************************
406  * EnumConnectionsImpl_QueryInterface (IUnknown)
407  *
408  * See Windows documentation for more details on IUnknown methods.
409  */
410 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
411   IEnumConnections*  iface,
412   REFIID  riid,
413   void**  ppvObject)
414 {
415   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
416   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
417 
418   /*
419    * Perform a sanity check on the parameters.
420    */
421   if ( (This==0) || (ppvObject==0) )
422     return E_INVALIDARG;
423 
424   /*
425    * Initialize the return parameter.
426    */
427   *ppvObject = 0;
428 
429   /*
430    * Compare the riid with the interface IDs implemented by this object.
431    */
432   if (IsEqualIID(&IID_IUnknown, riid))
433     *ppvObject = This;
434   else if (IsEqualIID(&IID_IEnumConnections, riid))
435     *ppvObject = This;
436 
437   /*
438    * Check that we obtained an interface.
439    */
440   if ((*ppvObject)==0)
441   {
442     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
443     return E_NOINTERFACE;
444   }
445 
446   /*
447    * Query Interface always increases the reference count by one when it is
448    * successful
449    */
450   EnumConnectionsImpl_AddRef((IEnumConnections*)This);
451 
452   return S_OK;
453 }
454 
455 
456 /************************************************************************
457  * EnumConnectionsImpl_AddRef (IUnknown)
458  *
459  * See Windows documentation for more details on IUnknown methods.
460  */
461 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
462 {
463   EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
464   ULONG refCount = InterlockedIncrement(&This->ref);
465 
466   TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
467 
468   IUnknown_AddRef(This->pUnk);
469   return refCount;
470 }
471 
472 /************************************************************************
473  * EnumConnectionsImpl_Release (IUnknown)
474  *
475  * See Windows documentation for more details on IUnknown methods.
476  */
477 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
478 {
479   EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
480   ULONG refCount = InterlockedDecrement(&This->ref);
481 
482   TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
483 
484   IUnknown_Release(This->pUnk);
485 
486   /*
487    * If the reference count goes down to 0, perform suicide.
488    */
489   if (!refCount) EnumConnectionsImpl_Destroy(This);
490 
491   return refCount;
492 }
493 
494 /************************************************************************
495  * EnumConnectionsImpl_Next (IEnumConnections)
496  *
497  */
498 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
499 					       ULONG cConn, LPCONNECTDATA pCD,
500 					       ULONG *pEnum)
501 {
502   EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
503   DWORD nRet = 0;
504   TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum);
505 
506   if(pEnum == NULL) {
507     if(cConn != 1)
508       return E_POINTER;
509   } else
510     *pEnum = 0;
511 
512   if(This->nCur >= This->nConns)
513     return S_FALSE;
514 
515   while(This->nCur < This->nConns && cConn) {
516     *pCD++ = This->pCD[This->nCur];
517     IUnknown_AddRef(This->pCD[This->nCur].pUnk);
518     This->nCur++;
519     cConn--;
520     nRet++;
521   }
522 
523   if(pEnum)
524     *pEnum = nRet;
525 
526   return S_OK;
527 }
528 
529 
530 /************************************************************************
531  * EnumConnectionsImpl_Skip (IEnumConnections)
532  *
533  */
534 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
535 					       ULONG cSkip)
536 {
537   EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
538   TRACE("(%p)->(%d)\n", This, cSkip);
539 
540   if(This->nCur + cSkip >= This->nConns)
541     return S_FALSE;
542 
543   This->nCur += cSkip;
544 
545   return S_OK;
546 }
547 
548 
549 /************************************************************************
550  * EnumConnectionsImpl_Reset (IEnumConnections)
551  *
552  */
553 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
554 {
555   EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
556   TRACE("(%p)\n", This);
557 
558   This->nCur = 0;
559 
560   return S_OK;
561 }
562 
563 
564 /************************************************************************
565  * EnumConnectionsImpl_Clone (IEnumConnections)
566  *
567  */
568 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
569 						LPENUMCONNECTIONS *ppEnum)
570 {
571   EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
572   EnumConnectionsImpl *newObj;
573   TRACE("(%p)->(%p)\n", This, ppEnum);
574 
575   newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
576   newObj->nCur = This->nCur;
577   *ppEnum = (LPENUMCONNECTIONS)newObj;
578   IUnknown_AddRef(This->pUnk);
579   return S_OK;
580 }
581 
582 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
583 {
584   EnumConnectionsImpl_QueryInterface,
585   EnumConnectionsImpl_AddRef,
586   EnumConnectionsImpl_Release,
587   EnumConnectionsImpl_Next,
588   EnumConnectionsImpl_Skip,
589   EnumConnectionsImpl_Reset,
590   EnumConnectionsImpl_Clone
591 };
592 
593 /************************************************************************
594  *
595  *  The exported function to create the connection point.
596  *  NB not a windows API
597  *
598  * PARAMS
599  * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
600  *           Needed to access IConnectionPointContainer.
601  *
602  * riid [in] IID of sink interface that this ConnectionPoint manages
603  *
604  * pCP [out] returns IConnectionPoint
605  *
606  */
607 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
608 			      IConnectionPoint **pCP)
609 {
610   ConnectionPointImpl *Obj;
611   HRESULT hr;
612 
613   Obj = ConnectionPointImpl_Construct(pUnk, riid);
614   if(!Obj) return E_OUTOFMEMORY;
615 
616   hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj,
617 				       &IID_IConnectionPoint, (LPVOID)pCP);
618   IConnectionPoint_Release((IConnectionPoint *)Obj);
619   return hr;
620 }
621