/////////////////////////////////////////////////////////////////////////////// /* File: connect.cpp Description: Contains class definitions for classes associated with OLE connection points. These are: ConnectionPoint ( IConnectionPoint ) ConnectionPointEnum ( IEnumConnectionPoints ) ConnectionEnum ( IEnumConnections ) Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// #include "pch.h" // PCH #pragma hdrstop #include "connect.h" #include "guidsp.h" // // Constants for connection point-related objects. // const UINT CONNECTION_FIRST_COOKIE = 100; // 1st cookie value given out. // // Verify that build is UNICODE. // #if !defined(UNICODE) # error This module must be compiled UNICODE. #endif /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::ConnectionPoint Description: Constructor, Arguments: pUnkContainer - Pointer to containing DiskQuotaController object. riid - Reference to IID that this connection point object supports. Returns: Nothing. Exceptions: CAllocException, CSyncException Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu 09/06/96 Added exception handling. BrianAu */ /////////////////////////////////////////////////////////////////////////////// ConnectionPoint::ConnectionPoint( LPUNKNOWN pUnkContainer, REFIID riid ) : m_cRef(0), m_cConnections(0), m_dwCookieNext(CONNECTION_FIRST_COOKIE), m_pUnkContainer(pUnkContainer), m_riid(riid), m_hMutex(NULL) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPoint::ConnectionPoint"))); DBGASSERT((NULL != pUnkContainer)); if (NULL == (m_hMutex = CreateMutex(NULL, FALSE, NULL))) throw CSyncException(CSyncException::mutex, CSyncException::create); m_Dispatch.Initialize(static_cast(this), LIBID_DiskQuotaTypeLibrary, IID_DIDiskQuotaControlEvents, L"DSKQUOTA.DLL"); } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::~ConnectionPoint Description: Destructor. Arguments: None. Returns: Nothing. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// ConnectionPoint::~ConnectionPoint( VOID ) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPoint::~ConnectionPoint"))); Lock(); UINT cConnections = m_ConnectionList.Count(); for (UINT i = 0; i < cConnections; i++) { if (NULL != m_ConnectionList[i].pUnk) { m_ConnectionList[i].pUnk->Release(); } } ReleaseLock(); if (NULL != m_hMutex) CloseHandle(m_hMutex); } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::QueryInterface Description: Returns an interface pointer to the object's IUnknown or IConnectionPoint interface. Only IID_IUnknown and IID_IConnectionPoint are recognized. The object referenced by the returned interface pointer is uninitialized. The recipient of the pointer must call Initialize() before the object is usable. Arguments: riid - Reference to requested interface ID. ppvOut - Address of interface pointer variable to accept interface ptr. Returns: NOERROR - Success. E_NOINTERFACE - Requested interface not supported. E_INVALIDARG - ppvOut argument was NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPoint::QueryInterface( REFIID riid, LPVOID *ppvOut ) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPoint::QueryInterface"))); DBGPRINTIID(DM_CONNPT, DL_MID, riid); HRESULT hr = E_NOINTERFACE; if (NULL == ppvOut) return E_INVALIDARG; *ppvOut = NULL; if (IID_IUnknown == riid || IID_IConnectionPoint == riid) { *ppvOut = static_cast(this); } else if (IID_IDispatch == riid) { *ppvOut = static_cast(this); } if (NULL != *ppvOut) { ((LPUNKNOWN)*ppvOut)->AddRef(); hr = NOERROR; } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::AddRef Description: Increments object reference count. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) ConnectionPoint::AddRef( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPoint::AddRef"))); ULONG cRef = InterlockedIncrement(&m_cRef); // // NOTE: We maintain a pointer to the quota controller (m_pUnkContainer) but // we DO NOT AddRef it. The controller calls AddRef for connection // point objects so this would create a circular reference. // DBGPRINT((DM_CONNPT, DL_LOW, TEXT("\t0x%08X %d -> %d\n"), this, cRef - 1, cRef )); return cRef; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::Release Description: Decrements object reference count. If count drops to 0, object is deleted. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) ConnectionPoint::Release( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPoint::Release"))); ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); DBGPRINT((DM_COM, DL_HIGH, TEXT("\t0x%08X %d -> %d\n"), this, cRef + 1, cRef)); if ( 0 == cRef ) { delete this; } return cRef; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::GetConnectionInterface Description: Retrieves a connection point's interface ID. Arguments: pIID - Address of IID variable to receive the IID. Returns: NOERROR - Success. E_INVALIDARG - pIID is NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPoint::GetConnectionInterface( LPIID pIID ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::GetConnectionInterface"))); HRESULT hr = E_INVALIDARG; if (NULL != pIID) { *pIID = m_riid; hr = NOERROR; } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::GetConnectionPointContainer Description: Retrieves an interface pointer for the point's parent container. Arguments: ppCPC - Address of variable to receive container's interface pointer value. Returns: NOERROR - Success. E_INVALIDARG - ppCPC argument was NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPoint::GetConnectionPointContainer( PCONNECTIONPOINTCONTAINER *ppCPC ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::GetConnectionPointContainer"))); return m_pUnkContainer->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)ppCPC); } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::Advise Description: Notifies the connection point of an outgoing interface. Arguments: pUnkSink - Pointer to outgoing interface provided by Sink. pdwCookie - Address of variable to receive the "cookie" returned for this connection. The client uses this "cookie" value to refer to the connection. Returns: NOERROR - Success. E_INVALIDARG - pUnkSink or pdwCookie were NULL. CONNECT_E_CANNOTCONNECT - Sink doesn't support our event interface. E_UNEXPECTED - Exception caught while calling client code. E_OUTOFMEMORY - Insufficient memory. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 07/21/96 Initial creation. BrianAu 09/06/96 Added exception handling. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPoint::Advise( LPUNKNOWN pUnkSink, LPDWORD pdwCookie ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::Advise"))); DBGPRINT((DM_CONNPT, DL_MID, TEXT("\tAdvising connpt 0x%08X of sink 0x%08X"), this, pUnkSink)); HRESULT hr = NOERROR; if (NULL == pUnkSink || NULL == pdwCookie) return E_INVALIDARG; LPUNKNOWN pSink = NULL; AutoLockMutex lock(m_hMutex); // // Does the sink support our conn pt interface? // try { // // QueryInterface() is client code. Must handle exceptions. // hr = pUnkSink->QueryInterface(m_riid, (LPVOID *)&pSink); if (SUCCEEDED(hr)) { CONNECTDATA cd; // // See if there is an unused entry in the list. // If not, we'll have to extend the list. // UINT index = m_cConnections; for (UINT i = 0; i < m_cConnections; i++) { if (NULL == m_ConnectionList[i].pUnk) { index = i; break; } } // // Fill in the connection info and add to connection list. // cd.pUnk = pSink; *pdwCookie = cd.dwCookie = m_dwCookieNext++; if (index < m_cConnections) m_ConnectionList[index] = cd; else m_ConnectionList.Append(cd); // This can throw OutOfMemory. if (SUCCEEDED(hr)) { m_cConnections++; // Another connection. DBGPRINT((DM_CONNPT, DL_HIGH, TEXT("CONNPT - Connection complete. Cookie = %d. %d total connections."), *pdwCookie, m_cConnections)); } else { DBGERROR((TEXT("ConnPt connection failed with error 0x%08X."), hr)); } } else hr = CONNECT_E_CANNOTCONNECT; // Interface not supported. } catch(CAllocException& e) { DBGERROR((TEXT("Insufficient memory exception"))); hr = E_OUTOFMEMORY; } if (FAILED(hr) && NULL != pSink) { // // Something failed after QueryInterface. Release sink pointer. // pSink->Release(); } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::Unadvise Description: Disconntinues an outgoing communication channel with the connection point object. Arguments: dwCookie - The "channel" identifier returned from Advise(). Returns: NOERROR - Success. CONNECT_E_NOCONNECTION - No connection found for this cookie. E_UNEXPECTED - Exception caught while calling client code. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 07/21/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPoint::Unadvise( DWORD dwCookie ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::Unadvise"))); DBGPRINT((DM_CONNPT, DL_MID, TEXT("\tUnadvising connpt 0x%08X of cookie %d"), this, dwCookie)); HRESULT hr = CONNECT_E_NOCONNECTION; if (0 != dwCookie) { AutoLockMutex lock(m_hMutex); for (UINT i = 0; i < m_cConnections; i++) { if (m_ConnectionList[i].dwCookie == dwCookie) { // // Matching cookie found. Release interface, mark connection // list entry as unused. // hr = NOERROR; m_ConnectionList[i].pUnk->Release(); m_ConnectionList[i].pUnk = NULL; m_ConnectionList[i].dwCookie = 0; m_cConnections--; DBGPRINT((DM_CONNPT, DL_HIGH, TEXT("CONNPT - Connection terminated for cookie %d. %d total connections"), dwCookie, m_cConnections)); break; } } } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPoint::EnumConnections Description: Retrieves in interface pointer to a connection enumerator which enumerates all connections associated with this connection point. Arguments: ppEnum - Address of interface pointer variable to received address of the enumerator's IEnumConnection interface. Returns: NOERROR - Success. E_INVALIDARG - ppEnum was NULL. E_OUTOFMEMORY - Insufficient memory to create enumerator. E_UNEXPECTED - Unexpected exception. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 07/21/96 Initial creation. BrianAu 09/06/96 Added exception handling. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPoint::EnumConnections( PENUMCONNECTIONS *ppEnum ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::EnumConnections"))); HRESULT hr = NOERROR; if (NULL == ppEnum) return E_INVALIDARG; ConnectionEnum *pEnum = NULL; AutoLockMutex lock(m_hMutex); try { array_autoptr ptrCD; PCONNECTDATA pcd = NULL; // // Build temp array of connection data to initialize enumerator. // Note: If m_cConnections == 0, we still return an enumerator // but it's uninitialized. Calls to Next and Skip will always // return S_FALSE so the enumerator is just viewed as "empty". // if (0 != m_cConnections) { ptrCD = new CONNECTDATA[m_cConnections]; pcd = ptrCD.get(); // // Transfer connection info to temp array for initializting // the enumerator object. // Remember, the connection list can have unused entries so // cConnListEntries can be greater than m_cConnections. // UINT cConnListEntries = m_ConnectionList.Count(); for (UINT i = 0, j = 0; i < cConnListEntries; i++) { DBGASSERT((j < m_cConnections)); *(pcd + j) = m_ConnectionList[i]; if (NULL != pcd[j].pUnk) j++; } } // // Create the enumerator object. // The enumerator keeps a copy of the connection's // IUnknown pointer. Note that we still create an // enumerator even if m_cConnections is 0. It's just an // empty enumerator. If m_cConnections is 0, pcd can be NULL. // DBGASSERT((m_cConnections ? NULL != pcd : TRUE)); pEnum = new ConnectionEnum(static_cast(this), m_cConnections, pcd); hr = pEnum->QueryInterface(IID_IEnumConnections, (LPVOID *)ppEnum); } catch(CAllocException& e) { DBGERROR((TEXT("Insufficient memory exception"))); delete pEnum; hr = E_OUTOFMEMORY; } return hr; } // // IDispatch::GetIDsOfNames // STDMETHODIMP ConnectionPoint::GetIDsOfNames( REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::GetIDsOfNames"))); // // Let our dispatch object handle this. // return m_Dispatch.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId); } // // IDispatch::GetTypeInfo // STDMETHODIMP ConnectionPoint::GetTypeInfo( UINT iTInfo, LCID lcid, ITypeInfo **ppTypeInfo ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::GetTypeInfo"))); // // Let our dispatch object handle this. // return m_Dispatch.GetTypeInfo(iTInfo, lcid, ppTypeInfo); } // // IDispatch::GetTypeInfoCount // STDMETHODIMP ConnectionPoint::GetTypeInfoCount( UINT *pctinfo ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::GetTypeInfoCount"))); // // Let our dispatch object handle this. // return m_Dispatch.GetTypeInfoCount(pctinfo); } // // IDispatch::Invoke // STDMETHODIMP ConnectionPoint::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionPoint::Invoke"))); // // Let our dispatch object handle this. // return m_Dispatch.Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::ConnectionEnum Description: Constructor, Arguments: pUnkContainer - Pointer to the IUnknown interface of the containing object. cConnections - Number of connections in array pointed to by rgConnections. rgConnections - Array of connection information used to initialize the enumerator. Returns: Nothing. Exceptions: CAllocException. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu 09/06/06 Added copy constructor. BrianAu */ /////////////////////////////////////////////////////////////////////////////// ConnectionEnum::ConnectionEnum( LPUNKNOWN pUnkContainer, UINT cConnections, PCONNECTDATA rgConnections ) : m_cRef(0), m_iCurrent(0), m_cConnections(0), m_rgConnections(NULL), m_pUnkContainer(pUnkContainer) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionEnum::ConnectionEnum"))); DBGASSERT((NULL != pUnkContainer)); if (0 != cConnections) { m_rgConnections = new CONNECTDATA[cConnections]; DBGASSERT((NULL != rgConnections)); for (UINT i = 0; i < cConnections; i++) { // // IUnknown::AddRef() is client code. It can generate an exception. // Caller must catch and handle it. // rgConnections[i].pUnk->AddRef(); m_rgConnections[i].pUnk = rgConnections[i].pUnk; m_rgConnections[i].dwCookie = rgConnections[i].dwCookie; m_cConnections++; } } } ConnectionEnum::ConnectionEnum(const ConnectionEnum& refEnum) : m_cRef(0), m_iCurrent(0), m_cConnections(0), m_rgConnections(NULL), m_pUnkContainer(m_pUnkContainer) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionEnum::ConnectionEnum [copy]"))); if (0 != m_cConnections) { m_rgConnections = new CONNECTDATA[m_cConnections]; DBGASSERT((NULL != refEnum.m_rgConnections)); for (UINT i = 0; i < m_cConnections; i++) { // // IUnknown::AddRef() is client code. It can generate an exception. // Caller must catch and handle it. // refEnum.m_rgConnections[i].pUnk->AddRef(); m_rgConnections[i].pUnk = refEnum.m_rgConnections[i].pUnk; m_rgConnections[i].dwCookie = refEnum.m_rgConnections[i].dwCookie; m_cConnections++; } } } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::~ConnectionEnum Description: Destructor. Releases all connection sink interface pointers held in enumerator's array. Arguments: None. Returns: Nothing. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// ConnectionEnum::~ConnectionEnum( VOID ) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionEnum::~ConnectionEnum"))); if (NULL != m_rgConnections) { for (UINT i = 0; i < m_cConnections; i++) { if (NULL != m_rgConnections[i].pUnk) { m_rgConnections[i].pUnk->Release(); m_rgConnections[i].pUnk = NULL; } } delete[] m_rgConnections; } } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::QueryInterface Description: Returns an interface pointer to the object's IUnknown or IEnumConnections interface. Only IID_IUnknown and IID_IEnumConnections are recognized. The object referenced by the returned interface pointer is uninitialized. The recipient of the pointer must call Initialize() before the object is usable. Arguments: riid - Reference to requested interface ID. ppvOut - Address of interface pointer variable to accept interface ptr. Returns: NOERROR - Success. E_NOINTERFACE - Requested interface not supported. E_INVALIDARG - ppvOut arg is NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionEnum::QueryInterface( REFIID riid, LPVOID *ppvOut ) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionEnum::QueryInterface"))); DBGPRINTIID(DM_CONNPT, DL_MID, riid); HRESULT hr = E_NOINTERFACE; if (NULL == ppvOut) return E_INVALIDARG; *ppvOut = NULL; if (IID_IUnknown == riid || IID_IEnumConnections == riid) { *ppvOut = this; ((LPUNKNOWN)*ppvOut)->AddRef(); hr = NOERROR; } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::AddRef Description: Increments object reference count. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) ConnectionEnum::AddRef( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionEnum::AddRef"))); ULONG cRef = InterlockedIncrement(&m_cRef); // // Increment ref count of connection point so that it stays around // while the connection enumerator is alive. // DBGPRINT((DM_CONNPT, DL_LOW, TEXT("\t0x%08X %d -> %d\n"), this, cRef - 1, cRef )); m_pUnkContainer->AddRef(); return cRef; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::Release Description: Decrements object reference count. If count drops to 0, object is deleted. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) ConnectionEnum::Release( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionEnum::Release"))); DBGPRINT((DM_CONNPT, DL_LOW, TEXT("\t0x%08X %d -> %d\n"), this, m_cRef, m_cRef - 1)); ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); // // Decrement ref count of connection point. We AddRef'd it // above. // m_pUnkContainer->Release(); if ( 0 == cRef) { delete this; } return cRef; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::Next Description: Retrieve the next cConnections connections supported by the enumerator. Arguments: cConnections - Number of elements in pConnections array. pConnections - Array to receive CONNECTDATA data records. pcCreated [optional] - Address of DWORD to accept the count of records returned in pConnections. Note that any array locations equal to or beyond the value returned in pcCreated are invalid and set to NULL. Returns: S_OK - Success. Enumerated number of requested connections. S_FALSE - End of enumeration encountered. Returning less than cConnections records. E_INVALIDARG - pConnections arg is NULL. E_UNEXPECTED - Exception caught. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT ConnectionEnum::Next( DWORD cConnections, // Number of elements in array. PCONNECTDATA pConnections, // Dest array for connection info. DWORD *pcCreated // Return number created. ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionEnum::Next"))); if (NULL == pConnections) return E_INVALIDARG; HRESULT hr = S_OK; DWORD cCreated = 0; // // Transfer data to caller's array. // Stop when at the end of the enumeration or we've // returned all that the caller asked for. // while(m_iCurrent < m_cConnections && cConnections > 0) { DBGASSERT((NULL != m_rgConnections)); *pConnections = m_rgConnections[m_iCurrent++]; if (NULL != pConnections->pUnk) { pConnections->pUnk->AddRef(); pConnections++; cCreated++; cConnections--; } } // // If requested, return the count of items enumerated. // if (NULL != pcCreated) *pcCreated = cCreated; if (cConnections > 0) { // // Less than requested number of connections were retrieved. // hr = S_FALSE; while(cConnections > 0) { // // Set any un-filled array elements to NULL. // pConnections->pUnk = NULL; pConnections->dwCookie = 0; pConnections++; cConnections--; } } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::Skip Description: Skips a specified number of connections in the enumeration. Arguments: cConnections - Number of connections to skip. Returns: S_OK - Success. Skipped number of requested items. S_FALSE - End of enumeration encountered. Skipped less than cConnections items. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionEnum::Skip( DWORD cConnections ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionEnum::Skip"))); while(m_iCurrent < m_cConnections && cConnections > 0) { m_iCurrent++; cConnections--; } return cConnections == 0 ? S_OK : S_FALSE; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::Reset Description: Resets the enumerator object so that the next call to Next() starts enumerating at the beginning of the enumeration. Arguments: None. Returns: S_OK - Success. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionEnum::Reset( VOID ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionEnum::Reset"))); m_iCurrent = 0; return S_OK; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionEnum::Clone Description: Creates a duplicate of the enumerator object and returns a pointer to the new object's IEnumConnections interface. Arguments: ppEnum - Address of interface pointer variable to accept the pointer to the new object's IEnumConnections interface. Returns: NOERROR - Success. E_OUTOFMEMORY - Insufficient memory to create new enumerator. E_INVALIDARG - ppEnum arg was NULL. E_UNEXPECTED - Exception caught while calling client code. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionEnum::Clone( PENUMCONNECTIONS *ppEnum ) { DBGTRACE((DM_CONNPT, DL_HIGH, TEXT("ConnectionEnum::Clone"))); if (NULL == ppEnum) return E_INVALIDARG; HRESULT hr = NOERROR; ConnectionEnum *pEnum = NULL; *ppEnum = NULL; try { pEnum = new ConnectionEnum((const ConnectionEnum&)*this); hr = pEnum->QueryInterface(IID_IEnumConnections, (LPVOID *)ppEnum); } catch(CAllocException& e) { DBGERROR((TEXT("Insufficient memory exception"))); hr = E_OUTOFMEMORY; } if (FAILED(hr) && NULL != pEnum) { delete pEnum; *ppEnum = NULL; } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::ConnectionPointEnum Description: Constructor, Arguments: pUnkContainer - Pointer to IUnknown of containing object. cConnPts - Number of connection points in array pointed to by rgConnPts. rgConnPts - Array of connection point object pointers used to initialize the enumerator. Returns: Nothing. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu 09/06/96 Added copy constructor. BrianAu */ /////////////////////////////////////////////////////////////////////////////// ConnectionPointEnum::ConnectionPointEnum( LPUNKNOWN pUnkContainer, UINT cConnPts, PCONNECTIONPOINT *rgConnPts ) : m_cRef(0), m_iCurrent(0), m_cConnPts(0), m_rgConnPts(NULL), m_pUnkContainer(pUnkContainer) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPointEnum::ConnectionPointEnum"))); DBGASSERT((NULL != pUnkContainer)); if (0 != cConnPts) { m_rgConnPts = new PCONNECTIONPOINT[cConnPts]; m_cConnPts = cConnPts; for (UINT i = 0; i < m_cConnPts; i++) { m_rgConnPts[i] = rgConnPts[i]; m_rgConnPts[i]->AddRef(); } } } ConnectionPointEnum::ConnectionPointEnum( const ConnectionPointEnum& refEnum ) : m_cRef(0), m_iCurrent(0), m_cConnPts(0), m_rgConnPts(NULL), m_pUnkContainer(refEnum.m_pUnkContainer) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPointEnum::ConnectionPointEnum [copy]"))); if (0 != refEnum.m_cConnPts) { m_rgConnPts = new PCONNECTIONPOINT[refEnum.m_cConnPts]; m_cConnPts = refEnum.m_cConnPts; for (UINT i = 0; i < m_cConnPts; i++) { m_rgConnPts[i] = refEnum.m_rgConnPts[i]; m_rgConnPts[i]->AddRef(); } } } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::~ConnectionPointEnum Description: Destructor. Releases all connection point object pointers held in enumerator's array. Arguments: None. Returns: Nothing. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// ConnectionPointEnum::~ConnectionPointEnum( VOID ) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPointEnum::~ConnectionPointEnum"))); if (NULL != m_rgConnPts) { for (UINT i = 0; i < m_cConnPts; i++) { if (NULL != m_rgConnPts[i]) { m_rgConnPts[i]->Release(); m_rgConnPts[i] = NULL; } } delete[] m_rgConnPts; } } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::QueryInterface Description: Returns an interface pointer to the object's IUnknown or IEnumConnectionPoints interface. Only IID_IUnknown and IID_IEnumConnectionPoints are recognized. The object referenced by the returned interface pointer is uninitialized. The recipient of the pointer must call Initialize() before the object is usable. Arguments: riid - Reference to requested interface ID. ppvOut - Address of interface pointer variable to accept interface ptr. Returns: NOERROR - Success. E_NOINTERFACE - Requested interface not supported. E_INVALIDARG - ppvOut argument was NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPointEnum::QueryInterface( REFIID riid, LPVOID *ppvOut ) { DBGTRACE((DM_CONNPT, DL_MID, TEXT("ConnectionPointEnum::QueryInterface"))); DBGPRINTIID(DM_CONNPT, DL_MID, riid); HRESULT hr = E_NOINTERFACE; if (NULL == ppvOut) return E_INVALIDARG; *ppvOut = NULL; if (IID_IUnknown == riid || IID_IEnumConnectionPoints == riid) { *ppvOut = this; ((LPUNKNOWN)*ppvOut)->AddRef(); hr = NOERROR; } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::AddRef Description: Increments object reference count. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) ConnectionPointEnum::AddRef( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPointEnum::AddRef"))); ULONG cRef = InterlockedIncrement(&m_cRef); // // Increment ref count of QuotaController so that it stays around // while the enumerator is alive. // DBGPRINT((DM_CONNPT, DL_LOW, TEXT("\t0x%08X %d -> %d\n"), this, cRef - 1, cRef )); m_pUnkContainer->AddRef(); return cRef; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::Release Description: Decrements object reference count. If count drops to 0, object is deleted. Arguments: None. Returns: New reference count value. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/18/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) ConnectionPointEnum::Release( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPointEnum::Release"))); ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); DBGPRINT((DM_COM, DL_HIGH, TEXT("\t0x%08X %d -> %d\n"), this, cRef + 1, cRef)); // // Decrement ref count of QuotaController. We AddRef'd it above. // m_pUnkContainer->Release(); if ( 0 == cRef ) { delete this; } return cRef; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::Next Description: Retrieve the next cConnPts connections supported by the enumerator. Arguments: cConnPts - Number of elements in pConnPts array. pConnPts - Array to receive PCONNECTIONPOINT pointers. pcCreated [optional] - Address of DWORD to accept the count of records returned in pConnPts. Note that any array locations equal to or beyond the value returned in pcCreated are invalid and set to NULL. Returns: S_OK - Success. Enumerated number of requested connection pts. S_FALSE - End of enumeration encountered. Returning less than cConnPts records. E_INVALIDARG - pConnPts arg is NULL. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// HRESULT ConnectionPointEnum::Next( DWORD cConnPts, // Number of elements in array. PCONNECTIONPOINT *rgpConnPts, // Dest array for connection point ptrs. DWORD *pcCreated // Return number created. ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPointEnum::Next"))); if (NULL == rgpConnPts) return E_INVALIDARG; HRESULT hr = S_OK; DWORD cCreated = 0; // // Transfer data to caller's array. // Stop when at the end of the enumeration or we've // returned all that the caller asked for. // while(m_iCurrent < m_cConnPts && cConnPts > 0) { *rgpConnPts = m_rgConnPts[m_iCurrent++]; if (NULL != *rgpConnPts) { (*rgpConnPts)->AddRef(); rgpConnPts++; cCreated++; cConnPts--; } else DBGASSERT((FALSE)); // Shouldn't hit this. } // // If requested, return the count of items enumerated. // if (NULL != pcCreated) *pcCreated = cCreated; if (cConnPts > 0) { // // Less than requested number of connections were retrieved. // hr = S_FALSE; while(cConnPts > 0) { // // Set any un-filled array elements to NULL. // *rgpConnPts = NULL; rgpConnPts++; cConnPts--; } } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::Skip Description: Skips a specified number of connection pts in the enumeration. Arguments: cConnPts - Number of connection points to skip. Returns: S_OK - Success. Skipped number of requested items. S_FALSE - End of enumeration encountered. Skipped less than cConnPts items. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPointEnum::Skip( DWORD cConnPts ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPointEnum::Skip"))); while(m_iCurrent < m_cConnPts && cConnPts > 0) { m_iCurrent++; cConnPts--; } return cConnPts == 0 ? S_OK : S_FALSE; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::Reset Description: Resets the enumerator object so that the next call to Next() starts enumerating at the start of the enumeration. Arguments: None. Returns: S_OK - Success. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPointEnum::Reset( VOID ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPointEnum::Reset"))); m_iCurrent = 0; return S_OK; } /////////////////////////////////////////////////////////////////////////////// /* Function: ConnectionPointEnum::Clone Description: Creates a duplicate of the enumerator object and returns a pointer to the new object's IEnumConnectionPoints interface. Arguments: ppEnum - Address of interface pointer variable to accept the pointer to the new object's IEnumConnectionPoints interface. Returns: NOERROR - Success. E_OUTOFMEMORY - Insufficient memory to create new enumerator. E_INVALIDARG - ppEnum arg was NULL. E_UNEXPECTED - Unexpected exception. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 06/19/96 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP ConnectionPointEnum::Clone( PENUMCONNECTIONPOINTS *ppEnum ) { DBGTRACE((DM_CONNPT, DL_LOW, TEXT("ConnectionPointEnum::Clone"))); if (NULL == ppEnum) return E_INVALIDARG; HRESULT hr = NOERROR; ConnectionPointEnum *pEnum = NULL; try { *ppEnum = NULL; pEnum = new ConnectionPointEnum((const ConnectionPointEnum&)*this); hr = pEnum->QueryInterface(IID_IEnumConnectionPoints, (LPVOID *)ppEnum); } catch(CAllocException& e) { DBGERROR((TEXT("Insufficient memory exception"))); hr = E_OUTOFMEMORY; } if (FAILED(hr) && NULL != pEnum) { delete pEnum; *ppEnum = NULL; } return hr; }