push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / oleaut32 / connpt.c
blob94e8e7cd2a5f44ff0cf29e8753d52a7c9b68f32e
1 /*
2 * Implementation of a generic ConnectionPoint object.
4 * Copyright 2000 Huw D M Davies for CodeWeavers
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.
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.
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
20 * NOTES:
21 * See one exported function here is CreateConnectionPoint, see
22 * comments just above that function for information.
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
29 #define COBJMACROS
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"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
44 #define MAXSINKS 10
46 /************************************************************************
47 * Implementation of IConnectionPoint
49 typedef struct ConnectionPointImpl {
51 const IConnectionPointVtbl *lpvtbl;
53 /* IUnknown of our main object*/
54 IUnknown *Obj;
56 /* Reference count */
57 LONG ref;
59 /* IID of sink interface */
60 IID iid;
62 /* Array of sink IUnknowns */
63 IUnknown **sinks;
64 DWORD maxSinks;
66 DWORD nSinks;
67 } ConnectionPointImpl;
69 static const IConnectionPointVtbl ConnectionPointImpl_VTable;
72 /************************************************************************
73 * Implementation of IEnumConnections
75 typedef struct EnumConnectionsImpl {
77 const IEnumConnectionsVtbl *lpvtbl;
79 LONG ref;
81 /* IUnknown of ConnectionPoint, used for ref counting */
82 IUnknown *pUnk;
84 /* Connection Data */
85 CONNECTDATA *pCD;
86 DWORD nConns;
88 /* Next connection to enumerate from */
89 DWORD nCur;
91 } EnumConnectionsImpl;
93 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
94 DWORD nSinks,
95 CONNECTDATA *pCD);
98 /************************************************************************
99 * ConnectionPointImpl_Construct
101 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
102 REFIID riid)
104 ConnectionPointImpl *Obj;
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;
118 /************************************************************************
119 * ConnectionPointImpl_Destroy
121 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
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;
130 HeapFree(GetProcessHeap(), 0, Obj->sinks);
131 HeapFree(GetProcessHeap(), 0, Obj);
132 return;
135 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
136 /************************************************************************
137 * ConnectionPointImpl_QueryInterface (IUnknown)
139 * See Windows documentation for more details on IUnknown methods.
141 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
142 IConnectionPoint* iface,
143 REFIID riid,
144 void** ppvObject)
146 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
147 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
150 * Perform a sanity check on the parameters.
152 if ( (This==0) || (ppvObject==0) )
153 return E_INVALIDARG;
156 * Initialize the return parameter.
158 *ppvObject = 0;
161 * Compare the riid with the interface IDs implemented by this object.
163 if (IsEqualIID(&IID_IUnknown, riid))
164 *ppvObject = This;
165 else if (IsEqualIID(&IID_IConnectionPoint, riid))
166 *ppvObject = This;
169 * Check that we obtained an interface.
171 if ((*ppvObject)==0)
173 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
174 return E_NOINTERFACE;
178 * Query Interface always increases the reference count by one when it is
179 * successful
181 ConnectionPointImpl_AddRef((IConnectionPoint*)This);
183 return S_OK;
187 /************************************************************************
188 * ConnectionPointImpl_AddRef (IUnknown)
190 * See Windows documentation for more details on IUnknown methods.
192 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
194 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
195 ULONG refCount = InterlockedIncrement(&This->ref);
197 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
199 return refCount;
202 /************************************************************************
203 * ConnectionPointImpl_Release (IUnknown)
205 * See Windows documentation for more details on IUnknown methods.
207 static ULONG WINAPI ConnectionPointImpl_Release(
208 IConnectionPoint* iface)
210 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
211 ULONG refCount = InterlockedDecrement(&This->ref);
213 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
216 * If the reference count goes down to 0, perform suicide.
218 if (!refCount) ConnectionPointImpl_Destroy(This);
220 return refCount;
223 /************************************************************************
224 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
227 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
228 IConnectionPoint *iface,
229 IID *piid)
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;
237 /************************************************************************
238 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
241 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
242 IConnectionPoint *iface,
243 IConnectionPointContainer **ppCPC)
245 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
246 TRACE("(%p)->(%p)\n", This, ppCPC);
248 return IUnknown_QueryInterface(This->Obj,
249 &IID_IConnectionPointContainer,
250 (LPVOID)ppCPC);
253 /************************************************************************
254 * ConnectionPointImpl_Advise (IConnectionPoint)
257 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
258 IUnknown *lpUnk,
259 DWORD *pdwCookie)
261 DWORD i;
262 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
263 IUnknown *lpSink;
264 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
266 *pdwCookie = 0;
267 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
268 return CONNECT_E_CANNOTCONNECT;
270 for(i = 0; i < This->maxSinks; i++) {
271 if(This->sinks[i] == NULL)
272 break;
274 if(i == This->maxSinks) {
275 This->maxSinks += MAXSINKS;
276 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
277 This->maxSinks * sizeof(IUnknown *));
279 This->sinks[i] = lpSink;
280 This->nSinks++;
281 *pdwCookie = i + 1;
282 return S_OK;
286 /************************************************************************
287 * ConnectionPointImpl_Unadvise (IConnectionPoint)
290 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
291 DWORD dwCookie)
293 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
294 TRACE("(%p)->(%d)\n", This, dwCookie);
296 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
298 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
300 IUnknown_Release(This->sinks[dwCookie-1]);
301 This->sinks[dwCookie-1] = NULL;
302 This->nSinks--;
303 return S_OK;
306 /************************************************************************
307 * ConnectionPointImpl_EnumConnections (IConnectionPoint)
310 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
311 IConnectionPoint *iface,
312 LPENUMCONNECTIONS *ppEnum)
314 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
315 CONNECTDATA *pCD;
316 DWORD i, nextslot;
317 EnumConnectionsImpl *EnumObj;
318 HRESULT hr;
320 TRACE("(%p)->(%p)\n", This, ppEnum);
322 *ppEnum = NULL;
324 if(This->nSinks == 0) return OLE_E_NOCONNECTION;
326 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
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++;
335 assert(nextslot == This->nSinks);
337 /* Bump the ref count of this object up by one. It gets Released in
338 IEnumConnections_Release */
339 IUnknown_AddRef((IUnknown*)This);
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);
346 HeapFree(GetProcessHeap(), 0, pCD);
347 return hr;
350 static const IConnectionPointVtbl ConnectionPointImpl_VTable =
352 ConnectionPointImpl_QueryInterface,
353 ConnectionPointImpl_AddRef,
354 ConnectionPointImpl_Release,
355 ConnectionPointImpl_GetConnectionInterface,
356 ConnectionPointImpl_GetConnectionPointContainer,
357 ConnectionPointImpl_Advise,
358 ConnectionPointImpl_Unadvise,
359 ConnectionPointImpl_EnumConnections
363 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
364 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
366 /************************************************************************
367 * EnumConnectionsImpl_Construct
369 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
370 DWORD nSinks,
371 CONNECTDATA *pCD)
373 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
374 DWORD i;
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;
383 for(i = 0; i < nSinks; i++) {
384 Obj->pCD[i] = pCD[i];
385 IUnknown_AddRef(Obj->pCD[i].pUnk);
387 return Obj;
390 /************************************************************************
391 * EnumConnectionsImpl_Destroy
393 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
395 DWORD i;
397 for(i = 0; i < Obj->nConns; i++)
398 IUnknown_Release(Obj->pCD[i].pUnk);
400 HeapFree(GetProcessHeap(), 0, Obj->pCD);
401 HeapFree(GetProcessHeap(), 0, Obj);
402 return;
405 /************************************************************************
406 * EnumConnectionsImpl_QueryInterface (IUnknown)
408 * See Windows documentation for more details on IUnknown methods.
410 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
411 IEnumConnections* iface,
412 REFIID riid,
413 void** ppvObject)
415 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
416 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
419 * Perform a sanity check on the parameters.
421 if ( (This==0) || (ppvObject==0) )
422 return E_INVALIDARG;
425 * Initialize the return parameter.
427 *ppvObject = 0;
430 * Compare the riid with the interface IDs implemented by this object.
432 if (IsEqualIID(&IID_IUnknown, riid))
433 *ppvObject = This;
434 else if (IsEqualIID(&IID_IEnumConnections, riid))
435 *ppvObject = This;
438 * Check that we obtained an interface.
440 if ((*ppvObject)==0)
442 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
443 return E_NOINTERFACE;
447 * Query Interface always increases the reference count by one when it is
448 * successful
450 EnumConnectionsImpl_AddRef((IEnumConnections*)This);
452 return S_OK;
456 /************************************************************************
457 * EnumConnectionsImpl_AddRef (IUnknown)
459 * See Windows documentation for more details on IUnknown methods.
461 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
463 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
464 ULONG refCount = InterlockedIncrement(&This->ref);
466 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
468 IUnknown_AddRef(This->pUnk);
469 return refCount;
472 /************************************************************************
473 * EnumConnectionsImpl_Release (IUnknown)
475 * See Windows documentation for more details on IUnknown methods.
477 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
479 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
480 ULONG refCount = InterlockedDecrement(&This->ref);
482 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
484 IUnknown_Release(This->pUnk);
487 * If the reference count goes down to 0, perform suicide.
489 if (!refCount) EnumConnectionsImpl_Destroy(This);
491 return refCount;
494 /************************************************************************
495 * EnumConnectionsImpl_Next (IEnumConnections)
498 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
499 ULONG cConn, LPCONNECTDATA pCD,
500 ULONG *pEnum)
502 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
503 DWORD nRet = 0;
504 TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum);
506 if(pEnum == NULL) {
507 if(cConn != 1)
508 return E_POINTER;
509 } else
510 *pEnum = 0;
512 if(This->nCur >= This->nConns)
513 return S_FALSE;
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++;
523 if(pEnum)
524 *pEnum = nRet;
526 return S_OK;
530 /************************************************************************
531 * EnumConnectionsImpl_Skip (IEnumConnections)
534 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
535 ULONG cSkip)
537 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
538 TRACE("(%p)->(%d)\n", This, cSkip);
540 if(This->nCur + cSkip >= This->nConns)
541 return S_FALSE;
543 This->nCur += cSkip;
545 return S_OK;
549 /************************************************************************
550 * EnumConnectionsImpl_Reset (IEnumConnections)
553 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
555 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
556 TRACE("(%p)\n", This);
558 This->nCur = 0;
560 return S_OK;
564 /************************************************************************
565 * EnumConnectionsImpl_Clone (IEnumConnections)
568 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
569 LPENUMCONNECTIONS *ppEnum)
571 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
572 EnumConnectionsImpl *newObj;
573 TRACE("(%p)->(%p)\n", This, ppEnum);
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;
582 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
584 EnumConnectionsImpl_QueryInterface,
585 EnumConnectionsImpl_AddRef,
586 EnumConnectionsImpl_Release,
587 EnumConnectionsImpl_Next,
588 EnumConnectionsImpl_Skip,
589 EnumConnectionsImpl_Reset,
590 EnumConnectionsImpl_Clone
593 /************************************************************************
595 * The exported function to create the connection point.
596 * NB not a windows API
598 * PARAMS
599 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
600 * Needed to access IConnectionPointContainer.
602 * riid [in] IID of sink interface that this ConnectionPoint manages
604 * pCP [out] returns IConnectionPoint
607 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
608 IConnectionPoint **pCP)
610 ConnectionPointImpl *Obj;
611 HRESULT hr;
613 Obj = ConnectionPointImpl_Construct(pUnk, riid);
614 if(!Obj) return E_OUTOFMEMORY;
616 hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj,
617 &IID_IConnectionPoint, (LPVOID)pCP);
618 IConnectionPoint_Release((IConnectionPoint *)Obj);
619 return hr;