Ref count increment/decrement cleanup.
[wine/testsucceed.git] / dlls / oleaut32 / connpt.c
blob1e6c45f7611aa939239de8c512e40ca5147e2979
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "ole2.h"
34 #include "olectl.h"
35 #include "connpt.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41 #define MAXSINKS 10
43 /************************************************************************
44 * Implementation of IConnectionPoint
46 typedef struct ConnectionPointImpl {
48 IConnectionPointVtbl *lpvtbl;
50 /* IUnknown of our main object*/
51 IUnknown *Obj;
53 /* Reference count */
54 DWORD ref;
56 /* IID of sink interface */
57 IID iid;
59 /* Array of sink IUnknowns */
60 IUnknown **sinks;
61 DWORD maxSinks;
63 DWORD nSinks;
64 } ConnectionPointImpl;
66 static IConnectionPointVtbl ConnectionPointImpl_VTable;
69 /************************************************************************
70 * Implementation of IEnumConnections
72 typedef struct EnumConnectionsImpl {
74 IEnumConnectionsVtbl *lpvtbl;
76 DWORD ref;
78 /* IUnknown of ConnectionPoint, used for ref counting */
79 IUnknown *pUnk;
81 /* Connection Data */
82 CONNECTDATA *pCD;
83 DWORD nConns;
85 /* Next connection to enumerate from */
86 DWORD nCur;
88 } EnumConnectionsImpl;
90 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
91 DWORD nSinks,
92 CONNECTDATA *pCD);
95 /************************************************************************
96 * ConnectionPointImpl_Construct
98 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
99 REFIID riid)
101 ConnectionPointImpl *Obj;
103 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
104 Obj->lpvtbl = &ConnectionPointImpl_VTable;
105 Obj->Obj = pUnk;
106 Obj->ref = 1;
107 Obj->iid = *riid;
108 Obj->maxSinks = MAXSINKS;
109 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
110 sizeof(IUnknown*) * MAXSINKS);
111 Obj->nSinks = 0;
112 return Obj;
115 /************************************************************************
116 * ConnectionPointImpl_Destroy
118 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
120 DWORD i;
121 for(i = 0; i < Obj->maxSinks; i++) {
122 if(Obj->sinks[i]) {
123 IUnknown_Release(Obj->sinks[i]);
124 Obj->sinks[i] = NULL;
127 HeapFree(GetProcessHeap(), 0, Obj->sinks);
128 HeapFree(GetProcessHeap(), 0, Obj);
129 return;
132 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
133 /************************************************************************
134 * ConnectionPointImpl_QueryInterface (IUnknown)
136 * See Windows documentation for more details on IUnknown methods.
138 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
139 IConnectionPoint* iface,
140 REFIID riid,
141 void** ppvObject)
143 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
144 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
147 * Perform a sanity check on the parameters.
149 if ( (This==0) || (ppvObject==0) )
150 return E_INVALIDARG;
153 * Initialize the return parameter.
155 *ppvObject = 0;
158 * Compare the riid with the interface IDs implemented by this object.
160 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
162 *ppvObject = (IConnectionPoint*)This;
164 else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0)
166 *ppvObject = (IConnectionPoint*)This;
170 * Check that we obtained an interface.
172 if ((*ppvObject)==0)
174 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
175 return E_NOINTERFACE;
179 * Query Interface always increases the reference count by one when it is
180 * successful
182 ConnectionPointImpl_AddRef((IConnectionPoint*)This);
184 return S_OK;
188 /************************************************************************
189 * ConnectionPointImpl_AddRef (IUnknown)
191 * See Windows documentation for more details on IUnknown methods.
193 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
195 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
196 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
197 return InterlockedIncrement(&This->ref);
200 /************************************************************************
201 * ConnectionPointImpl_Release (IUnknown)
203 * See Windows documentation for more details on IUnknown methods.
205 static ULONG WINAPI ConnectionPointImpl_Release(
206 IConnectionPoint* iface)
208 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
209 ULONG ref;
210 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
213 * Decrease the reference count on this object.
215 ref = InterlockedDecrement(&This->ref);
218 * If the reference count goes down to 0, perform suicide.
220 if (ref == 0) ConnectionPointImpl_Destroy(This);
222 return ref;
225 /************************************************************************
226 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
229 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
230 IConnectionPoint *iface,
231 IID *piid)
233 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
234 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
235 *piid = This->iid;
236 return S_OK;
239 /************************************************************************
240 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
243 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
244 IConnectionPoint *iface,
245 IConnectionPointContainer **ppCPC)
247 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
248 TRACE("(%p)->(%p)\n", This, ppCPC);
250 return IUnknown_QueryInterface(This->Obj,
251 &IID_IConnectionPointContainer,
252 (LPVOID)ppCPC);
255 /************************************************************************
256 * ConnectionPointImpl_Advise (IConnectionPoint)
259 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
260 IUnknown *lpUnk,
261 DWORD *pdwCookie)
263 DWORD i;
264 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
265 IUnknown *lpSink;
266 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
268 *pdwCookie = 0;
269 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
270 return CONNECT_E_CANNOTCONNECT;
272 for(i = 0; i < This->maxSinks; i++) {
273 if(This->sinks[i] == NULL)
274 break;
276 if(i == This->maxSinks) {
277 This->maxSinks += MAXSINKS;
278 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
279 This->maxSinks * sizeof(IUnknown *));
281 This->sinks[i] = lpSink;
282 This->nSinks++;
283 *pdwCookie = i + 1;
284 return S_OK;
288 /************************************************************************
289 * ConnectionPointImpl_Unadvise (IConnectionPoint)
292 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
293 DWORD dwCookie)
295 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
296 TRACE("(%p)->(%ld)\n", This, dwCookie);
298 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
300 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
302 IUnknown_Release(This->sinks[dwCookie-1]);
303 This->sinks[dwCookie-1] = NULL;
304 This->nSinks--;
305 return S_OK;
308 /************************************************************************
309 * ConnectionPointImpl_EnumConnections (IConnectionPoint)
312 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
313 IConnectionPoint *iface,
314 LPENUMCONNECTIONS *ppEnum)
316 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
317 CONNECTDATA *pCD;
318 DWORD i, nextslot;
319 EnumConnectionsImpl *EnumObj;
320 HRESULT hr;
322 TRACE("(%p)->(%p)\n", This, ppEnum);
324 *ppEnum = NULL;
326 if(This->nSinks == 0) return OLE_E_NOCONNECTION;
328 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
330 for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
331 if(This->sinks[i] != NULL) {
332 pCD[nextslot].pUnk = This->sinks[i];
333 pCD[nextslot].dwCookie = i + 1;
334 nextslot++;
337 assert(nextslot == This->nSinks);
339 /* Bump the ref count of this object up by one. It gets Released in
340 IEnumConnections_Release */
341 IUnknown_AddRef((IUnknown*)This);
343 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
344 hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj,
345 &IID_IEnumConnections, (LPVOID)ppEnum);
346 IEnumConnections_Release((IEnumConnections*)EnumObj);
348 HeapFree(GetProcessHeap(), 0, pCD);
349 return hr;
352 static IConnectionPointVtbl ConnectionPointImpl_VTable =
354 ConnectionPointImpl_QueryInterface,
355 ConnectionPointImpl_AddRef,
356 ConnectionPointImpl_Release,
357 ConnectionPointImpl_GetConnectionInterface,
358 ConnectionPointImpl_GetConnectionPointContainer,
359 ConnectionPointImpl_Advise,
360 ConnectionPointImpl_Unadvise,
361 ConnectionPointImpl_EnumConnections
365 static IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
366 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
368 /************************************************************************
369 * EnumConnectionsImpl_Construct
371 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
372 DWORD nSinks,
373 CONNECTDATA *pCD)
375 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
376 DWORD i;
378 Obj->lpvtbl = &EnumConnectionsImpl_VTable;
379 Obj->ref = 1;
380 Obj->pUnk = pUnk;
381 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
382 Obj->nConns = nSinks;
383 Obj->nCur = 0;
385 for(i = 0; i < nSinks; i++) {
386 Obj->pCD[i] = pCD[i];
387 IUnknown_AddRef(Obj->pCD[i].pUnk);
389 return Obj;
392 /************************************************************************
393 * EnumConnectionsImpl_Destroy
395 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
397 DWORD i;
399 for(i = 0; i < Obj->nConns; i++)
400 IUnknown_Release(Obj->pCD[i].pUnk);
402 HeapFree(GetProcessHeap(), 0, Obj->pCD);
403 HeapFree(GetProcessHeap(), 0, Obj);
404 return;
407 /************************************************************************
408 * EnumConnectionsImpl_QueryInterface (IUnknown)
410 * See Windows documentation for more details on IUnknown methods.
412 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
413 IEnumConnections* iface,
414 REFIID riid,
415 void** ppvObject)
417 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
418 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
421 * Perform a sanity check on the parameters.
423 if ( (This==0) || (ppvObject==0) )
424 return E_INVALIDARG;
427 * Initialize the return parameter.
429 *ppvObject = 0;
432 * Compare the riid with the interface IDs implemented by this object.
434 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
436 *ppvObject = (IEnumConnections*)This;
438 else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0)
440 *ppvObject = (IEnumConnections*)This;
444 * Check that we obtained an interface.
446 if ((*ppvObject)==0)
448 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
449 return E_NOINTERFACE;
453 * Query Interface always increases the reference count by one when it is
454 * successful
456 EnumConnectionsImpl_AddRef((IEnumConnections*)This);
458 return S_OK;
462 /************************************************************************
463 * EnumConnectionsImpl_AddRef (IUnknown)
465 * See Windows documentation for more details on IUnknown methods.
467 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
469 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
470 ULONG ref;
471 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
472 ref = InterlockedIncrement(&This->ref);
473 IUnknown_AddRef(This->pUnk);
474 return ref;
477 /************************************************************************
478 * EnumConnectionsImpl_Release (IUnknown)
480 * See Windows documentation for more details on IUnknown methods.
482 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
484 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
485 ULONG ref;
486 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
488 IUnknown_Release(This->pUnk);
491 * Decrease the reference count on this object.
493 ref = InterlockedDecrement(&This->ref);
496 * If the reference count goes down to 0, perform suicide.
498 if (ref == 0) EnumConnectionsImpl_Destroy(This);
500 return ref;
503 /************************************************************************
504 * EnumConnectionsImpl_Next (IEnumConnections)
507 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
508 ULONG cConn, LPCONNECTDATA pCD,
509 ULONG *pEnum)
511 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
512 DWORD nRet = 0;
513 TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum);
515 if(pEnum == NULL) {
516 if(cConn != 1)
517 return E_POINTER;
518 } else
519 *pEnum = 0;
521 if(This->nCur >= This->nConns)
522 return S_FALSE;
524 while(This->nCur < This->nConns && cConn) {
525 *pCD++ = This->pCD[This->nCur];
526 IUnknown_AddRef(This->pCD[This->nCur].pUnk);
527 This->nCur++;
528 cConn--;
529 nRet++;
532 if(pEnum)
533 *pEnum = nRet;
535 return S_OK;
539 /************************************************************************
540 * EnumConnectionsImpl_Skip (IEnumConnections)
543 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
544 ULONG cSkip)
546 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
547 TRACE("(%p)->(%ld)\n", This, cSkip);
549 if(This->nCur + cSkip >= This->nConns)
550 return S_FALSE;
552 This->nCur += cSkip;
554 return S_OK;
558 /************************************************************************
559 * EnumConnectionsImpl_Reset (IEnumConnections)
562 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
564 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
565 TRACE("(%p)\n", This);
567 This->nCur = 0;
569 return S_OK;
573 /************************************************************************
574 * EnumConnectionsImpl_Clone (IEnumConnections)
577 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
578 LPENUMCONNECTIONS *ppEnum)
580 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
581 EnumConnectionsImpl *newObj;
582 TRACE("(%p)->(%p)\n", This, ppEnum);
584 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
585 newObj->nCur = This->nCur;
586 *ppEnum = (LPENUMCONNECTIONS)newObj;
587 IUnknown_AddRef(This->pUnk);
588 return S_OK;
591 static IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
593 EnumConnectionsImpl_QueryInterface,
594 EnumConnectionsImpl_AddRef,
595 EnumConnectionsImpl_Release,
596 EnumConnectionsImpl_Next,
597 EnumConnectionsImpl_Skip,
598 EnumConnectionsImpl_Reset,
599 EnumConnectionsImpl_Clone
602 /************************************************************************
604 * The exported function to create the connection point.
605 * NB not a windows API
607 * PARAMS
608 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
609 * Needed to access IConnectionPointContainer.
611 * riid [in] IID of sink interface that this ConnectionPoint manages
613 * pCP [out] returns IConnectionPoint
616 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
617 IConnectionPoint **pCP)
619 ConnectionPointImpl *Obj;
620 HRESULT hr;
622 Obj = ConnectionPointImpl_Construct(pUnk, riid);
623 if(!Obj) return E_OUTOFMEMORY;
625 hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj,
626 &IID_IConnectionPoint, (LPVOID)pCP);
627 IConnectionPoint_Release((IConnectionPoint *)Obj);
628 return hr;