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