xref: /reactos/dll/win32/oleaut32/connpt.c (revision f6f20487)
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 #define WIN32_NO_STATUS
26 #define _INC_WINDOWS
27 
28 #include <assert.h>
29 #include <stdarg.h>
30 //#include <string.h>
31 
32 #define COBJMACROS
33 
34 //#include "winerror.h"
35 #include <windef.h>
36 #include <winbase.h>
37 //#include "wingdi.h"
38 //#include "winuser.h"
39 #include <ole2.h>
40 #include <olectl.h>
41 //#include "connpt.h"
42 
43 #include <wine/debug.h>
44 
45 WINE_DEFAULT_DEBUG_CHANNEL(ole);
46 
47 #define MAXSINKS 10
48 
49 /************************************************************************
50  * Implementation of IConnectionPoint
51  */
52 typedef struct ConnectionPointImpl {
53 
54   IConnectionPoint IConnectionPoint_iface;
55 
56   /* IUnknown of our main object*/
57   IUnknown *Obj;
58 
59   /* Reference count */
60   LONG ref;
61 
62   /* IID of sink interface */
63   IID iid;
64 
65   /* Array of sink IUnknowns */
66   IUnknown **sinks;
67   DWORD maxSinks;
68 
69   DWORD nSinks;
70 } ConnectionPointImpl;
71 
72 static const IConnectionPointVtbl ConnectionPointImpl_VTable;
73 
74 
75 /************************************************************************
76  * Implementation of IEnumConnections
77  */
78 typedef struct EnumConnectionsImpl {
79 
80   IEnumConnections IEnumConnections_iface;
81 
82   LONG ref;
83 
84   /* IUnknown of ConnectionPoint, used for ref counting */
85   IUnknown *pUnk;
86 
87   /* Connection Data */
88   CONNECTDATA *pCD;
89   DWORD nConns;
90 
91   /* Next connection to enumerate from */
92   DWORD nCur;
93 
94 } EnumConnectionsImpl;
95 
96 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
97 							  DWORD nSinks,
98 							  CONNECTDATA *pCD);
99 
100 static inline ConnectionPointImpl *impl_from_IConnectionPoint(IConnectionPoint *iface)
101 {
102   return CONTAINING_RECORD(iface, ConnectionPointImpl, IConnectionPoint_iface);
103 }
104 
105 static inline EnumConnectionsImpl *impl_from_IEnumConnections(IEnumConnections *iface)
106 {
107   return CONTAINING_RECORD(iface, EnumConnectionsImpl, IEnumConnections_iface);
108 }
109 
110 /************************************************************************
111  * ConnectionPointImpl_Construct
112  */
113 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
114 							  REFIID riid)
115 {
116   ConnectionPointImpl *Obj;
117 
118   Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
119   Obj->IConnectionPoint_iface.lpVtbl = &ConnectionPointImpl_VTable;
120   Obj->Obj = pUnk;
121   Obj->ref = 1;
122   Obj->iid =  *riid;
123   Obj->maxSinks = MAXSINKS;
124   Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
125 			 sizeof(IUnknown*) * MAXSINKS);
126   Obj->nSinks = 0;
127   return Obj;
128 }
129 
130 /************************************************************************
131  * ConnectionPointImpl_Destroy
132  */
133 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
134 {
135   DWORD i;
136   for(i = 0; i < Obj->maxSinks; i++) {
137     if(Obj->sinks[i]) {
138       IUnknown_Release(Obj->sinks[i]);
139       Obj->sinks[i] = NULL;
140     }
141   }
142   HeapFree(GetProcessHeap(), 0, Obj->sinks);
143   HeapFree(GetProcessHeap(), 0, Obj);
144   return;
145 }
146 
147 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
148 /************************************************************************
149  * ConnectionPointImpl_QueryInterface (IUnknown)
150  *
151  * See Windows documentation for more details on IUnknown methods.
152  */
153 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
154   IConnectionPoint*  iface,
155   REFIID  riid,
156   void**  ppvObject)
157 {
158   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
159   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
160 
161   /*
162    * Perform a sanity check on the parameters.
163    */
164   if ( (This==0) || (ppvObject==0) )
165     return E_INVALIDARG;
166 
167   /*
168    * Initialize the return parameter.
169    */
170   *ppvObject = 0;
171 
172   /*
173    * Compare the riid with the interface IDs implemented by this object.
174    */
175   if (IsEqualIID(&IID_IUnknown, riid))
176     *ppvObject = This;
177   else if (IsEqualIID(&IID_IConnectionPoint, riid))
178     *ppvObject = This;
179 
180   /*
181    * Check that we obtained an interface.
182    */
183   if ((*ppvObject)==0)
184   {
185     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
186     return E_NOINTERFACE;
187   }
188 
189   /*
190    * Query Interface always increases the reference count by one when it is
191    * successful
192    */
193   ConnectionPointImpl_AddRef(&This->IConnectionPoint_iface);
194 
195   return S_OK;
196 }
197 
198 
199 /************************************************************************
200  * ConnectionPointImpl_AddRef (IUnknown)
201  *
202  * See Windows documentation for more details on IUnknown methods.
203  */
204 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
205 {
206   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
207   ULONG refCount = InterlockedIncrement(&This->ref);
208 
209   TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
210 
211   return refCount;
212 }
213 
214 /************************************************************************
215  * ConnectionPointImpl_Release (IUnknown)
216  *
217  * See Windows documentation for more details on IUnknown methods.
218  */
219 static ULONG WINAPI ConnectionPointImpl_Release(
220       IConnectionPoint* iface)
221 {
222   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
223   ULONG refCount = InterlockedDecrement(&This->ref);
224 
225   TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
226 
227   /*
228    * If the reference count goes down to 0, perform suicide.
229    */
230   if (!refCount) ConnectionPointImpl_Destroy(This);
231 
232   return refCount;
233 }
234 
235 /************************************************************************
236  * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
237  *
238  */
239 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
240 					       IConnectionPoint *iface,
241 					       IID              *piid)
242 {
243   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
244   TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
245   *piid = This->iid;
246   return S_OK;
247 }
248 
249 /************************************************************************
250  * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
251  *
252  */
253 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
254 				      IConnectionPoint           *iface,
255 				      IConnectionPointContainer  **ppCPC)
256 {
257   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
258   TRACE("(%p)->(%p)\n", This, ppCPC);
259 
260   return IUnknown_QueryInterface(This->Obj,
261 				 &IID_IConnectionPointContainer,
262 				 (LPVOID)ppCPC);
263 }
264 
265 /************************************************************************
266  * ConnectionPointImpl_Advise (IConnectionPoint)
267  *
268  */
269 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
270 						 IUnknown *lpUnk,
271 						 DWORD *pdwCookie)
272 {
273   DWORD i;
274   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
275   IUnknown *lpSink;
276   TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
277 
278   *pdwCookie = 0;
279   if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
280     return CONNECT_E_CANNOTCONNECT;
281 
282   for(i = 0; i < This->maxSinks; i++) {
283     if(This->sinks[i] == NULL)
284       break;
285   }
286   if(i == This->maxSinks) {
287     This->maxSinks += MAXSINKS;
288     This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
289 			      This->maxSinks * sizeof(IUnknown *));
290   }
291   This->sinks[i] = lpSink;
292   This->nSinks++;
293   *pdwCookie = i + 1;
294   return S_OK;
295 }
296 
297 
298 /************************************************************************
299  * ConnectionPointImpl_Unadvise (IConnectionPoint)
300  *
301  */
302 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
303 						   DWORD dwCookie)
304 {
305   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
306   TRACE("(%p)->(%d)\n", This, dwCookie);
307 
308   if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
309 
310   if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
311 
312   IUnknown_Release(This->sinks[dwCookie-1]);
313   This->sinks[dwCookie-1] = NULL;
314   This->nSinks--;
315   return S_OK;
316 }
317 
318 /************************************************************************
319  * ConnectionPointImpl_EnumConnections (IConnectionPoint)
320  *
321  */
322 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
323 						    IConnectionPoint *iface,
324 						    LPENUMCONNECTIONS *ppEnum)
325 {
326   ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
327   CONNECTDATA *pCD;
328   DWORD i, nextslot;
329   EnumConnectionsImpl *EnumObj;
330   HRESULT hr;
331 
332   TRACE("(%p)->(%p)\n", This, ppEnum);
333 
334   *ppEnum = NULL;
335 
336   if(This->nSinks == 0) return OLE_E_NOCONNECTION;
337 
338   pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
339 
340   for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
341     if(This->sinks[i] != NULL) {
342       pCD[nextslot].pUnk = This->sinks[i];
343       pCD[nextslot].dwCookie = i + 1;
344       nextslot++;
345     }
346   }
347   assert(nextslot == This->nSinks);
348 
349   /* Bump the ref count of this object up by one.  It gets Released in
350      IEnumConnections_Release */
351   IUnknown_AddRef((IUnknown*)This);
352 
353   EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
354   hr = IEnumConnections_QueryInterface(&EnumObj->IEnumConnections_iface,
355 				  &IID_IEnumConnections, (LPVOID)ppEnum);
356   IEnumConnections_Release(&EnumObj->IEnumConnections_iface);
357 
358   HeapFree(GetProcessHeap(), 0, pCD);
359   return hr;
360 }
361 
362 static const IConnectionPointVtbl ConnectionPointImpl_VTable =
363 {
364   ConnectionPointImpl_QueryInterface,
365   ConnectionPointImpl_AddRef,
366   ConnectionPointImpl_Release,
367   ConnectionPointImpl_GetConnectionInterface,
368   ConnectionPointImpl_GetConnectionPointContainer,
369   ConnectionPointImpl_Advise,
370   ConnectionPointImpl_Unadvise,
371   ConnectionPointImpl_EnumConnections
372 };
373 
374 
375 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
376 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
377 
378 /************************************************************************
379  * EnumConnectionsImpl_Construct
380  */
381 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
382 							  DWORD nSinks,
383 							  CONNECTDATA *pCD)
384 {
385   EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
386   DWORD i;
387 
388   Obj->IEnumConnections_iface.lpVtbl = &EnumConnectionsImpl_VTable;
389   Obj->ref = 1;
390   Obj->pUnk = pUnk;
391   Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
392   Obj->nConns = nSinks;
393   Obj->nCur = 0;
394 
395   for(i = 0; i < nSinks; i++) {
396     Obj->pCD[i] = pCD[i];
397     IUnknown_AddRef(Obj->pCD[i].pUnk);
398   }
399   return Obj;
400 }
401 
402 /************************************************************************
403  * EnumConnectionsImpl_Destroy
404  */
405 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
406 {
407   DWORD i;
408 
409   for(i = 0; i < Obj->nConns; i++)
410     IUnknown_Release(Obj->pCD[i].pUnk);
411 
412   HeapFree(GetProcessHeap(), 0, Obj->pCD);
413   HeapFree(GetProcessHeap(), 0, Obj);
414   return;
415 }
416 
417 /************************************************************************
418  * EnumConnectionsImpl_QueryInterface (IUnknown)
419  *
420  * See Windows documentation for more details on IUnknown methods.
421  */
422 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
423   IEnumConnections*  iface,
424   REFIID  riid,
425   void**  ppvObject)
426 {
427   ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
428   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
429 
430   /*
431    * Perform a sanity check on the parameters.
432    */
433   if ( (This==0) || (ppvObject==0) )
434     return E_INVALIDARG;
435 
436   /*
437    * Initialize the return parameter.
438    */
439   *ppvObject = 0;
440 
441   /*
442    * Compare the riid with the interface IDs implemented by this object.
443    */
444   if (IsEqualIID(&IID_IUnknown, riid))
445     *ppvObject = This;
446   else if (IsEqualIID(&IID_IEnumConnections, riid))
447     *ppvObject = This;
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   EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
476   ULONG refCount = InterlockedIncrement(&This->ref);
477 
478   TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
479 
480   IUnknown_AddRef(This->pUnk);
481   return refCount;
482 }
483 
484 /************************************************************************
485  * EnumConnectionsImpl_Release (IUnknown)
486  *
487  * See Windows documentation for more details on IUnknown methods.
488  */
489 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
490 {
491   EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
492   ULONG refCount = InterlockedDecrement(&This->ref);
493 
494   TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
495 
496   IUnknown_Release(This->pUnk);
497 
498   /*
499    * If the reference count goes down to 0, perform suicide.
500    */
501   if (!refCount) EnumConnectionsImpl_Destroy(This);
502 
503   return refCount;
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 = impl_from_IEnumConnections(iface);
515   DWORD nRet = 0;
516   TRACE("(%p)->(%d, %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 = impl_from_IEnumConnections(iface);
550   TRACE("(%p)->(%d)\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 = impl_from_IEnumConnections(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 = impl_from_IEnumConnections(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 const 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(&Obj->IConnectionPoint_iface,
629 				       &IID_IConnectionPoint, (LPVOID)pCP);
630   IConnectionPoint_Release(&Obj->IConnectionPoint_iface);
631   return hr;
632 }
633