wbemprox: Handle NULL out parameter to object methods.
[wine/wine-gecko.git] / dlls / oleaut32 / connpt.c
blob1d7b05ce5bf7df0bbed488231311087d2a4d7a86
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 IConnectionPoint IConnectionPoint_iface;
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 IEnumConnections IEnumConnections_iface;
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);
97 static inline ConnectionPointImpl *impl_from_IConnectionPoint(IConnectionPoint *iface)
99 return CONTAINING_RECORD(iface, ConnectionPointImpl, IConnectionPoint_iface);
102 static inline EnumConnectionsImpl *impl_from_IEnumConnections(IEnumConnections *iface)
104 return CONTAINING_RECORD(iface, EnumConnectionsImpl, IEnumConnections_iface);
107 /************************************************************************
108 * ConnectionPointImpl_Construct
110 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
111 REFIID riid)
113 ConnectionPointImpl *Obj;
115 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
116 Obj->IConnectionPoint_iface.lpVtbl = &ConnectionPointImpl_VTable;
117 Obj->Obj = pUnk;
118 Obj->ref = 1;
119 Obj->iid = *riid;
120 Obj->maxSinks = MAXSINKS;
121 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
122 sizeof(IUnknown*) * MAXSINKS);
123 Obj->nSinks = 0;
124 return Obj;
127 /************************************************************************
128 * ConnectionPointImpl_Destroy
130 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
132 DWORD i;
133 for(i = 0; i < Obj->maxSinks; i++) {
134 if(Obj->sinks[i]) {
135 IUnknown_Release(Obj->sinks[i]);
136 Obj->sinks[i] = NULL;
139 HeapFree(GetProcessHeap(), 0, Obj->sinks);
140 HeapFree(GetProcessHeap(), 0, Obj);
141 return;
144 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
145 /************************************************************************
146 * ConnectionPointImpl_QueryInterface (IUnknown)
148 * See Windows documentation for more details on IUnknown methods.
150 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
151 IConnectionPoint* iface,
152 REFIID riid,
153 void** ppvObject)
155 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
156 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
159 * Perform a sanity check on the parameters.
161 if ( (This==0) || (ppvObject==0) )
162 return E_INVALIDARG;
165 * Initialize the return parameter.
167 *ppvObject = 0;
170 * Compare the riid with the interface IDs implemented by this object.
172 if (IsEqualIID(&IID_IUnknown, riid))
173 *ppvObject = This;
174 else if (IsEqualIID(&IID_IConnectionPoint, riid))
175 *ppvObject = This;
178 * Check that we obtained an interface.
180 if ((*ppvObject)==0)
182 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
183 return E_NOINTERFACE;
187 * Query Interface always increases the reference count by one when it is
188 * successful
190 ConnectionPointImpl_AddRef(&This->IConnectionPoint_iface);
192 return S_OK;
196 /************************************************************************
197 * ConnectionPointImpl_AddRef (IUnknown)
199 * See Windows documentation for more details on IUnknown methods.
201 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
203 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
204 ULONG refCount = InterlockedIncrement(&This->ref);
206 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
208 return refCount;
211 /************************************************************************
212 * ConnectionPointImpl_Release (IUnknown)
214 * See Windows documentation for more details on IUnknown methods.
216 static ULONG WINAPI ConnectionPointImpl_Release(
217 IConnectionPoint* iface)
219 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
220 ULONG refCount = InterlockedDecrement(&This->ref);
222 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
225 * If the reference count goes down to 0, perform suicide.
227 if (!refCount) ConnectionPointImpl_Destroy(This);
229 return refCount;
232 /************************************************************************
233 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
236 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
237 IConnectionPoint *iface,
238 IID *piid)
240 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
241 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
242 *piid = This->iid;
243 return S_OK;
246 /************************************************************************
247 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
250 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
251 IConnectionPoint *iface,
252 IConnectionPointContainer **ppCPC)
254 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
255 TRACE("(%p)->(%p)\n", This, ppCPC);
257 return IUnknown_QueryInterface(This->Obj, &IID_IConnectionPointContainer, (void**)ppCPC);
260 /************************************************************************
261 * ConnectionPointImpl_Advise (IConnectionPoint)
264 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
265 IUnknown *lpUnk,
266 DWORD *pdwCookie)
268 DWORD i;
269 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
270 IUnknown *lpSink;
271 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
273 *pdwCookie = 0;
274 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (void**)&lpSink)))
275 return CONNECT_E_CANNOTCONNECT;
277 for(i = 0; i < This->maxSinks; i++) {
278 if(This->sinks[i] == NULL)
279 break;
281 if(i == This->maxSinks) {
282 This->maxSinks += MAXSINKS;
283 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
284 This->maxSinks * sizeof(IUnknown *));
286 This->sinks[i] = lpSink;
287 This->nSinks++;
288 *pdwCookie = i + 1;
289 return S_OK;
293 /************************************************************************
294 * ConnectionPointImpl_Unadvise (IConnectionPoint)
297 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
298 DWORD dwCookie)
300 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
301 TRACE("(%p)->(%d)\n", This, dwCookie);
303 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
305 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
307 IUnknown_Release(This->sinks[dwCookie-1]);
308 This->sinks[dwCookie-1] = NULL;
309 This->nSinks--;
310 return S_OK;
313 /************************************************************************
314 * ConnectionPointImpl_EnumConnections (IConnectionPoint)
317 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
318 IConnectionPoint *iface,
319 LPENUMCONNECTIONS *ppEnum)
321 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
322 CONNECTDATA *pCD;
323 DWORD i, nextslot;
324 EnumConnectionsImpl *EnumObj;
325 HRESULT hr;
327 TRACE("(%p)->(%p)\n", This, ppEnum);
329 *ppEnum = NULL;
331 if(This->nSinks == 0) return OLE_E_NOCONNECTION;
333 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
335 for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
336 if(This->sinks[i] != NULL) {
337 pCD[nextslot].pUnk = This->sinks[i];
338 pCD[nextslot].dwCookie = i + 1;
339 nextslot++;
342 assert(nextslot == This->nSinks);
344 /* Bump the ref count of this object up by one. It gets Released in
345 IEnumConnections_Release */
346 IUnknown_AddRef((IUnknown*)This);
348 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
349 hr = IEnumConnections_QueryInterface(&EnumObj->IEnumConnections_iface,
350 &IID_IEnumConnections, (void**)ppEnum);
351 IEnumConnections_Release(&EnumObj->IEnumConnections_iface);
353 HeapFree(GetProcessHeap(), 0, pCD);
354 return hr;
357 static const IConnectionPointVtbl ConnectionPointImpl_VTable =
359 ConnectionPointImpl_QueryInterface,
360 ConnectionPointImpl_AddRef,
361 ConnectionPointImpl_Release,
362 ConnectionPointImpl_GetConnectionInterface,
363 ConnectionPointImpl_GetConnectionPointContainer,
364 ConnectionPointImpl_Advise,
365 ConnectionPointImpl_Unadvise,
366 ConnectionPointImpl_EnumConnections
370 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
371 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
373 /************************************************************************
374 * EnumConnectionsImpl_Construct
376 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
377 DWORD nSinks,
378 CONNECTDATA *pCD)
380 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
381 DWORD i;
383 Obj->IEnumConnections_iface.lpVtbl = &EnumConnectionsImpl_VTable;
384 Obj->ref = 1;
385 Obj->pUnk = pUnk;
386 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
387 Obj->nConns = nSinks;
388 Obj->nCur = 0;
390 for(i = 0; i < nSinks; i++) {
391 Obj->pCD[i] = pCD[i];
392 IUnknown_AddRef(Obj->pCD[i].pUnk);
394 return Obj;
397 /************************************************************************
398 * EnumConnectionsImpl_Destroy
400 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
402 DWORD i;
404 for(i = 0; i < Obj->nConns; i++)
405 IUnknown_Release(Obj->pCD[i].pUnk);
407 HeapFree(GetProcessHeap(), 0, Obj->pCD);
408 HeapFree(GetProcessHeap(), 0, Obj);
409 return;
412 /************************************************************************
413 * EnumConnectionsImpl_QueryInterface (IUnknown)
415 * See Windows documentation for more details on IUnknown methods.
417 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
418 IEnumConnections* iface,
419 REFIID riid,
420 void** ppvObject)
422 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
423 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
426 * Perform a sanity check on the parameters.
428 if ( (This==0) || (ppvObject==0) )
429 return E_INVALIDARG;
432 * Initialize the return parameter.
434 *ppvObject = 0;
437 * Compare the riid with the interface IDs implemented by this object.
439 if (IsEqualIID(&IID_IUnknown, riid))
440 *ppvObject = This;
441 else if (IsEqualIID(&IID_IEnumConnections, riid))
442 *ppvObject = This;
445 * Check that we obtained an interface.
447 if ((*ppvObject)==0)
449 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
450 return E_NOINTERFACE;
454 * Query Interface always increases the reference count by one when it is
455 * successful
457 EnumConnectionsImpl_AddRef((IEnumConnections*)This);
459 return S_OK;
463 /************************************************************************
464 * EnumConnectionsImpl_AddRef (IUnknown)
466 * See Windows documentation for more details on IUnknown methods.
468 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
470 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
471 ULONG refCount = InterlockedIncrement(&This->ref);
473 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
475 IUnknown_AddRef(This->pUnk);
476 return refCount;
479 /************************************************************************
480 * EnumConnectionsImpl_Release (IUnknown)
482 * See Windows documentation for more details on IUnknown methods.
484 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
486 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
487 ULONG refCount = InterlockedDecrement(&This->ref);
489 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
491 IUnknown_Release(This->pUnk);
494 * If the reference count goes down to 0, perform suicide.
496 if (!refCount) EnumConnectionsImpl_Destroy(This);
498 return refCount;
501 /************************************************************************
502 * EnumConnectionsImpl_Next (IEnumConnections)
505 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
506 ULONG cConn, LPCONNECTDATA pCD,
507 ULONG *pEnum)
509 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
510 DWORD nRet = 0;
511 TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum);
513 if(pEnum == NULL) {
514 if(cConn != 1)
515 return E_POINTER;
516 } else
517 *pEnum = 0;
519 if(This->nCur >= This->nConns)
520 return S_FALSE;
522 while(This->nCur < This->nConns && cConn) {
523 *pCD++ = This->pCD[This->nCur];
524 IUnknown_AddRef(This->pCD[This->nCur].pUnk);
525 This->nCur++;
526 cConn--;
527 nRet++;
530 if(pEnum)
531 *pEnum = nRet;
533 return S_OK;
537 /************************************************************************
538 * EnumConnectionsImpl_Skip (IEnumConnections)
541 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
542 ULONG cSkip)
544 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
545 TRACE("(%p)->(%d)\n", This, cSkip);
547 if(This->nCur + cSkip >= This->nConns)
548 return S_FALSE;
550 This->nCur += cSkip;
552 return S_OK;
556 /************************************************************************
557 * EnumConnectionsImpl_Reset (IEnumConnections)
560 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
562 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
563 TRACE("(%p)\n", This);
565 This->nCur = 0;
567 return S_OK;
571 /************************************************************************
572 * EnumConnectionsImpl_Clone (IEnumConnections)
575 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
576 LPENUMCONNECTIONS *ppEnum)
578 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
579 EnumConnectionsImpl *newObj;
580 TRACE("(%p)->(%p)\n", This, ppEnum);
582 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
583 newObj->nCur = This->nCur;
584 *ppEnum = (LPENUMCONNECTIONS)newObj;
585 IUnknown_AddRef(This->pUnk);
586 return S_OK;
589 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
591 EnumConnectionsImpl_QueryInterface,
592 EnumConnectionsImpl_AddRef,
593 EnumConnectionsImpl_Release,
594 EnumConnectionsImpl_Next,
595 EnumConnectionsImpl_Skip,
596 EnumConnectionsImpl_Reset,
597 EnumConnectionsImpl_Clone
600 /************************************************************************
602 * The exported function to create the connection point.
603 * NB not a windows API
605 * PARAMS
606 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
607 * Needed to access IConnectionPointContainer.
609 * riid [in] IID of sink interface that this ConnectionPoint manages
611 * pCP [out] returns IConnectionPoint
614 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
615 IConnectionPoint **pCP)
617 ConnectionPointImpl *Obj;
618 HRESULT hr;
620 Obj = ConnectionPointImpl_Construct(pUnk, riid);
621 if(!Obj) return E_OUTOFMEMORY;
623 hr = IConnectionPoint_QueryInterface(&Obj->IConnectionPoint_iface,
624 &IID_IConnectionPoint, (void**)pCP);
625 IConnectionPoint_Release(&Obj->IConnectionPoint_iface);
626 return hr;