|  | /* | 
|  | * 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 <assert.h> | 
|  | #include "winerror.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.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; | 
|  | } |