/* * Implementation of a generic ConnectionPoint object. * * Copyright 2000 Huw D M Davies for CodeWeavers * * See one exported function here is CreateConnectionPoint, see * comments just above that function for information. */ #include #include "winerror.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "ole2.h" #include "olectl.h" #include "wine/obj_base.h" #include "wine/obj_connection.h" #include "connpt.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(ole); #define MAXSINKS 10 /************************************************************************ * Implementation of IConnectionPoint */ typedef struct ConnectionPointImpl { ICOM_VTABLE(IConnectionPoint) *lpvtbl; /* IUnknown of our main object*/ IUnknown *Obj; /* Reference count */ DWORD ref; /* IID of sink interface */ IID iid; /* Array of sink IUnknowns */ IUnknown **sinks; DWORD maxSinks; DWORD nSinks; } ConnectionPointImpl; static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable; /************************************************************************ * Implementation of IEnumConnections */ typedef struct EnumConnectionsImpl { ICOM_VTABLE(IEnumConnections) *lpvtbl; DWORD ref; /* IUnknown of ConnectionPoint, used for ref counting */ IUnknown *pUnk; /* Connection Data */ CONNECTDATA *pCD; DWORD nConns; /* Next connection to enumerate from */ DWORD nCur; } EnumConnectionsImpl; static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, DWORD nSinks, CONNECTDATA *pCD); /************************************************************************ * ConnectionPointImpl_Construct */ static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk, REFIID riid) { ConnectionPointImpl *Obj; Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); Obj->lpvtbl = &ConnectionPointImpl_VTable; Obj->Obj = pUnk; Obj->ref = 1; Obj->iid = *riid; Obj->maxSinks = MAXSINKS; Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IUnknown*) * MAXSINKS); Obj->nSinks = 0; return Obj; } /************************************************************************ * ConnectionPointImpl_Destroy */ static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj) { DWORD i; for(i = 0; i < Obj->maxSinks; i++) { if(Obj->sinks[i]) { IUnknown_Release(Obj->sinks[i]); Obj->sinks[i] = NULL; } } HeapFree(GetProcessHeap(), 0, Obj->sinks); HeapFree(GetProcessHeap(), 0, Obj); return; } static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface); /************************************************************************ * ConnectionPointImpl_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static HRESULT WINAPI ConnectionPointImpl_QueryInterface( IConnectionPoint* iface, REFIID riid, void** ppvObject) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); /* * Perform a sanity check on the parameters. */ if ( (This==0) || (ppvObject==0) ) return E_INVALIDARG; /* * Initialize the return parameter. */ *ppvObject = 0; /* * Compare the riid with the interface IDs implemented by this object. */ if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) { *ppvObject = (IConnectionPoint*)This; } else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0) { *ppvObject = (IConnectionPoint*)This; } /* * Check that we obtained an interface. */ if ((*ppvObject)==0) { FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); return E_NOINTERFACE; } /* * Query Interface always increases the reference count by one when it is * successful */ ConnectionPointImpl_AddRef((IConnectionPoint*)This); return S_OK;; } /************************************************************************ * ConnectionPointImpl_AddRef (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(ref=%ld)\n", This, This->ref); This->ref++; return This->ref; } /************************************************************************ * ConnectionPointImpl_Release (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI ConnectionPointImpl_Release( IConnectionPoint* iface) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(ref=%ld)\n", This, This->ref); /* * Decrease the reference count on this object. */ This->ref--; /* * If the reference count goes down to 0, perform suicide. */ if (This->ref==0) { ConnectionPointImpl_Destroy(This); return 0; } return This->ref; } /************************************************************************ * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint) * */ static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface( IConnectionPoint *iface, IID *piid) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid))); *piid = This->iid; return S_OK; } /************************************************************************ * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint) * */ static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer( IConnectionPoint *iface, IConnectionPointContainer **ppCPC) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(%p)\n", This, ppCPC); return IUnknown_QueryInterface(This->Obj, &IID_IConnectionPointContainer, (LPVOID)ppCPC); } /************************************************************************ * ConnectionPointImpl_Advise (IConnectionPoint) * */ static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface, IUnknown *lpUnk, DWORD *pdwCookie) { DWORD i; ICOM_THIS(ConnectionPointImpl, iface); IUnknown *lpSink; TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie); *pdwCookie = 0; if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink))) return CONNECT_E_CANNOTCONNECT; for(i = 0; i < This->maxSinks; i++) { if(This->sinks[i] == NULL) break; } if(i == This->maxSinks) { This->maxSinks += MAXSINKS; This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks, This->maxSinks * sizeof(IUnknown *)); } This->sinks[i] = lpSink; This->nSinks++; *pdwCookie = i + 1; return S_OK; } /************************************************************************ * ConnectionPointImpl_Unadvise (IConnectionPoint) * */ static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface, DWORD dwCookie) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(%ld)\n", This, dwCookie); if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG; if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION; IUnknown_Release(This->sinks[dwCookie-1]); This->sinks[dwCookie-1] = NULL; This->nSinks--; return S_OK; } /************************************************************************ * ConnectionPointImpl_EnumConnections (IConnectionPoint) * */ static HRESULT WINAPI ConnectionPointImpl_EnumConnections( IConnectionPoint *iface, LPENUMCONNECTIONS *ppEnum) { ICOM_THIS(ConnectionPointImpl, iface); CONNECTDATA *pCD; DWORD i, nextslot; EnumConnectionsImpl *EnumObj; HRESULT hr; TRACE("(%p)->(%p)\n", This, ppEnum); *ppEnum = NULL; if(This->nSinks == 0) return OLE_E_NOCONNECTION; pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks); for(i = 0, nextslot = 0; i < This->maxSinks; i++) { if(This->sinks[i] != NULL) { pCD[nextslot].pUnk = This->sinks[i]; pCD[nextslot].dwCookie = i + 1; nextslot++; } } assert(nextslot == This->nSinks); /* Bump the ref count of this object up by one. It gets Released in IEnumConnections_Release */ IUnknown_AddRef((IUnknown*)This); EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD); hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj, &IID_IEnumConnections, (LPVOID)ppEnum); IEnumConnections_Release((IEnumConnections*)EnumObj); HeapFree(GetProcessHeap(), 0, pCD); return hr; } static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE ConnectionPointImpl_QueryInterface, ConnectionPointImpl_AddRef, ConnectionPointImpl_Release, ConnectionPointImpl_GetConnectionInterface, ConnectionPointImpl_GetConnectionPointContainer, ConnectionPointImpl_Advise, ConnectionPointImpl_Unadvise, ConnectionPointImpl_EnumConnections }; static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable; static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface); /************************************************************************ * EnumConnectionsImpl_Construct */ static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, DWORD nSinks, CONNECTDATA *pCD) { EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); DWORD i; Obj->lpvtbl = &EnumConnectionsImpl_VTable; Obj->ref = 1; Obj->pUnk = pUnk; Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA)); Obj->nConns = nSinks; Obj->nCur = 0; for(i = 0; i < nSinks; i++) { Obj->pCD[i] = pCD[i]; IUnknown_AddRef(Obj->pCD[i].pUnk); } return Obj; } /************************************************************************ * EnumConnectionsImpl_Destroy */ static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj) { DWORD i; for(i = 0; i < Obj->nConns; i++) IUnknown_Release(Obj->pCD[i].pUnk); HeapFree(GetProcessHeap(), 0, Obj->pCD); HeapFree(GetProcessHeap(), 0, Obj); return; } /************************************************************************ * EnumConnectionsImpl_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static HRESULT WINAPI EnumConnectionsImpl_QueryInterface( IEnumConnections* iface, REFIID riid, void** ppvObject) { ICOM_THIS(ConnectionPointImpl, iface); TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); /* * Perform a sanity check on the parameters. */ if ( (This==0) || (ppvObject==0) ) return E_INVALIDARG; /* * Initialize the return parameter. */ *ppvObject = 0; /* * Compare the riid with the interface IDs implemented by this object. */ if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) { *ppvObject = (IEnumConnections*)This; } else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0) { *ppvObject = (IEnumConnections*)This; } /* * Check that we obtained an interface. */ if ((*ppvObject)==0) { FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); return E_NOINTERFACE; } /* * Query Interface always increases the reference count by one when it is * successful */ EnumConnectionsImpl_AddRef((IEnumConnections*)This); return S_OK;; } /************************************************************************ * EnumConnectionsImpl_AddRef (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface) { ICOM_THIS(EnumConnectionsImpl, iface); TRACE("(%p)->(ref=%ld)\n", This, This->ref); This->ref++; IUnknown_AddRef(This->pUnk); return This->ref; } /************************************************************************ * EnumConnectionsImpl_Release (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface) { ICOM_THIS(EnumConnectionsImpl, iface); TRACE("(%p)->(ref=%ld)\n", This, This->ref); IUnknown_Release(This->pUnk); /* * Decrease the reference count on this object. */ This->ref--; /* * If the reference count goes down to 0, perform suicide. */ if (This->ref==0) { EnumConnectionsImpl_Destroy(This); return 0; } return This->ref; } /************************************************************************ * EnumConnectionsImpl_Next (IEnumConnections) * */ static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface, ULONG cConn, LPCONNECTDATA pCD, ULONG *pEnum) { ICOM_THIS(EnumConnectionsImpl, iface); DWORD nRet = 0; TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum); if(pEnum == NULL) { if(cConn != 1) return E_POINTER; } else *pEnum = 0; if(This->nCur >= This->nConns) return S_FALSE; while(This->nCur < This->nConns && cConn) { *pCD++ = This->pCD[This->nCur]; IUnknown_AddRef(This->pCD[This->nCur].pUnk); This->nCur++; cConn--; nRet++; } if(pEnum) *pEnum = nRet; return S_OK; } /************************************************************************ * EnumConnectionsImpl_Skip (IEnumConnections) * */ static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface, ULONG cSkip) { ICOM_THIS(EnumConnectionsImpl, iface); TRACE("(%p)->(%ld)\n", This, cSkip); if(This->nCur + cSkip >= This->nConns) return S_FALSE; This->nCur += cSkip; return S_OK; } /************************************************************************ * EnumConnectionsImpl_Reset (IEnumConnections) * */ static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface) { ICOM_THIS(EnumConnectionsImpl, iface); TRACE("(%p)\n", This); This->nCur = 0; return S_OK; } /************************************************************************ * EnumConnectionsImpl_Clone (IEnumConnections) * */ static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface, LPENUMCONNECTIONS *ppEnum) { ICOM_THIS(EnumConnectionsImpl, iface); EnumConnectionsImpl *newObj; TRACE("(%p)->(%p)\n", This, ppEnum); newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD); newObj->nCur = This->nCur; *ppEnum = (LPENUMCONNECTIONS)newObj; IUnknown_AddRef(This->pUnk); return S_OK; } static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE EnumConnectionsImpl_QueryInterface, EnumConnectionsImpl_AddRef, EnumConnectionsImpl_Release, EnumConnectionsImpl_Next, EnumConnectionsImpl_Skip, EnumConnectionsImpl_Reset, EnumConnectionsImpl_Clone }; /************************************************************************ * * The exported function to create the connection point. * NB not a windows API * * PARAMS * pUnk [in] IUnknown of object to which the ConnectionPoint is associated. * Needed to access IConnectionPointContainer. * * riid [in] IID of sink interface that this ConnectionPoint manages * * pCP [out] returns IConnectionPoint * */ HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, IConnectionPoint **pCP) { ConnectionPointImpl *Obj; HRESULT hr; Obj = ConnectionPointImpl_Construct(pUnk, riid); if(!Obj) return E_OUTOFMEMORY; hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj, &IID_IConnectionPoint, (LPVOID)pCP); IConnectionPoint_Release((IConnectionPoint *)Obj); return hr; }