mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1109 lines
36 KiB
1109 lines
36 KiB
/*M*
|
|
// INTEL CORPORATION PROPRIETARY INFORMATION
|
|
// This software is supplied under the terms of a licence agreement or
|
|
// nondisclosure agreement with Intel Corporation and may not be copied
|
|
// or disclosed except in accordance with the terms of that agreement.
|
|
// Copyright (c) 1996 Intel Corporation. All Rights Reserved.
|
|
//
|
|
// Filename : Connect.cpp
|
|
// Purpose : Implementation file for a bunch of objects used
|
|
// to generically implement connection points.
|
|
// Contents :
|
|
*M*/
|
|
|
|
#ifndef _CONNECT_CPP_
|
|
#define _CONNECT_CPP_
|
|
|
|
#include "connect.h"
|
|
#include <wtypes.h>
|
|
|
|
// These GIUDs are defined in uuid.lib for C++ 4.2, but not in C++ 4.1 or
|
|
// earlier. Add them here for Data Router.
|
|
#if _MSC_VER < 1020
|
|
static const GUID IID_IConnectionPointContainer =
|
|
{0xB196B284,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
|
|
static const GUID IID_IEnumConnectionPoints =
|
|
{0xB196B285,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
|
|
static const GUID IID_IConnectionPoint =
|
|
{0xB196B286,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
|
|
static const GUID IID_IEnumConnections =
|
|
{0xB196B287,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
|
|
#endif
|
|
|
|
#include "autolock.h"
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::AddRef
|
|
// Purpose : Increment the reference count for this object.
|
|
// Context : Called by any program which wants to ensure
|
|
// that this object isn't destroyed before it
|
|
// says it is done with it (via Release(), below.)
|
|
// Called implicitly when a program successfully
|
|
// calls our QueryInterface() method.
|
|
// Returns : Current number of references held for this
|
|
// object.
|
|
// Params : None.
|
|
// Notes : Standard COM method.
|
|
*F*/
|
|
ULONG
|
|
CConnectionPointEnumerator::AddRef() {
|
|
CAutoLock l(&m_csState);
|
|
m_dwRefCount++;
|
|
return m_dwRefCount;
|
|
} /* CConnectionPointEnumerator::AddRef() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::CConnectionPointEnumerator()
|
|
// Purpose :
|
|
// Context :
|
|
// Returns :
|
|
// Params :
|
|
// iConnectList Reference to the list we are using.
|
|
// iConnectListCurrentPosition Iterator that indicates the
|
|
// entry in our connection list we
|
|
// are currently indicating.
|
|
// Notes :
|
|
*F*/
|
|
CConnectionPointEnumerator::CConnectionPointEnumerator(
|
|
list<CONNECTDATA>& lConnectList,
|
|
list<CONNECTDATA>::iterator iConnectListCurrentPosition) :
|
|
m_lConnectList(lConnectList),
|
|
m_iConnectListCurrentPosition(iConnectListCurrentPosition),
|
|
m_dwRefCount(0)
|
|
{
|
|
InitializeCriticalSection(&m_csState);
|
|
} /* CConnectionPointEnumerator::CConnectionPointEnumerator() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::~CConnectionPointEnumerator()
|
|
// Purpose :
|
|
// Context :
|
|
// Returns :
|
|
// Params :
|
|
// Notes :
|
|
*F*/
|
|
CConnectionPointEnumerator::~CConnectionPointEnumerator()
|
|
{
|
|
EnterCriticalSection(&m_csState);
|
|
LeaveCriticalSection(&m_csState);
|
|
DeleteCriticalSection(&m_csState);
|
|
} /* CConnectionPointEnumerator::CConnectionPointEnumerator() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::Clone()
|
|
// Purpose :
|
|
// Context :
|
|
// Returns :
|
|
// Params :
|
|
// Notes :
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointEnumerator::Clone(
|
|
IEnumConnections **ppEnum)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
CConnectionPointEnumerator *pNewConnPtEnum;
|
|
pNewConnPtEnum = new CConnectionPointEnumerator(m_lConnectList,
|
|
m_iConnectListCurrentPosition);
|
|
if (pNewConnPtEnum == (CConnectionPointEnumerator *) NULL) {
|
|
return E_OUTOFMEMORY;
|
|
} /* if */
|
|
|
|
HRESULT hErr;
|
|
hErr = pNewConnPtEnum->QueryInterface(IID_IEnumConnections,
|
|
(PVOID *) ppEnum);
|
|
if (FAILED(hErr)) {
|
|
delete pNewConnPtEnum;
|
|
} /* if */
|
|
|
|
return hErr;
|
|
} /* CConnectionPointEnumerator::Clone() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::Next
|
|
// Purpose :
|
|
// Context :
|
|
// Params :
|
|
// E_POINTER Invalid pcFetched parameter passed in.
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// S_FALSE No more connection points to return.
|
|
// Returns :
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointEnumerator::Next(
|
|
ULONG cConnections,
|
|
PCONNECTDATA pConnectData,
|
|
ULONG *pcFetched)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (IsBadWritePtr(pConnectData, cConnections * sizeof(CONNECTDATA))) {
|
|
return E_POINTER;
|
|
} /* if */
|
|
|
|
ULONG uTempCounter;
|
|
if ((cConnections == 1) && (pcFetched == (ULONG *) NULL)) {
|
|
// NULL is allowed to be passed in the pcFetched parameter
|
|
// when cConnections is 1, so rather than writing funny logic
|
|
// to worry about it I'll just create a temporary local to
|
|
// use instead.
|
|
pcFetched = &uTempCounter;
|
|
} /* if */
|
|
|
|
*pcFetched = 0;
|
|
while ((cConnections > 0) && (m_iConnectListCurrentPosition != m_lConnectList.end())) {
|
|
*pConnectData++ = *m_iConnectListCurrentPosition;
|
|
(*pcFetched)++;
|
|
m_iConnectListCurrentPosition++;
|
|
cConnections--;
|
|
} /* while */
|
|
|
|
if (*pcFetched > 0) {
|
|
// Successfully returned something.
|
|
return NOERROR;
|
|
} else {
|
|
// Nothing returned.
|
|
return S_FALSE;
|
|
} /* if */
|
|
} /* CConnectionPointEnumerator::Next() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::QueryInterface
|
|
// Purpose : Query us for our IConnectionPoint interface.
|
|
// Context :
|
|
// Returns : NOERROR if interface successfully found.
|
|
// E_NOINTERFACE otherwise.
|
|
// Params :
|
|
// riid IID of the desired interface
|
|
// ppv Pointer to a VOID * to store the
|
|
// returned interface in.
|
|
// Notes : Implicitly AddRef()s this object on success.
|
|
*F*/
|
|
STDMETHODIMP
|
|
CConnectionPointEnumerator::QueryInterface(
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (riid == IID_IEnumConnections) {
|
|
// Our own interface
|
|
*ppv = (IEnumConnections *) this;
|
|
} else if (riid == IID_IUnknown) {
|
|
*ppv = (IUnknown *) this;
|
|
} else {
|
|
return E_NOINTERFACE;
|
|
} /* if */
|
|
|
|
AddRef();
|
|
// Implicit AddRef(). The Release() must be explicitly done
|
|
// by the routine that called QueryInterface().
|
|
return NOERROR;
|
|
} /* CConnectionPointEnumerator::QueryInterface() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::Release
|
|
// Purpose : Decrement the reference count for this object.
|
|
// Context : Called by any program which holds a reference
|
|
// to this object which no longer needs it.
|
|
// Returns : Current reference count.
|
|
// Params : None.
|
|
// Notes : Should be called once for each AddRef()
|
|
// a program makes and once for each successful
|
|
// QueryInterface() a program made on us.
|
|
*F*/
|
|
ULONG
|
|
CConnectionPointEnumerator::Release() {
|
|
EnterCriticalSection(&m_csState);
|
|
m_dwRefCount--;
|
|
|
|
if (m_dwRefCount==0) {
|
|
LeaveCriticalSection(&m_csState);
|
|
delete this;
|
|
return 0;
|
|
}
|
|
LeaveCriticalSection(&m_csState);
|
|
return m_dwRefCount;
|
|
} /* CConnectionPointEnumerator::Release() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::Reset
|
|
// Purpose : Start the enumerator at the beginning of the
|
|
// connection point list again.
|
|
// Context : Any point after construction.
|
|
// Returns :
|
|
// NOERROR Successfully reset enumerator.
|
|
// Params : None.
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointEnumerator::Reset(void)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
m_iConnectListCurrentPosition = m_lConnectList.begin();
|
|
return NOERROR;
|
|
} /* CConnectionPointEnumerator::Reset() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointEnumerator::Skip
|
|
// Purpose : Skip forward over the specified number of connection points.
|
|
// Context :
|
|
// Params :
|
|
// uSkipCount Number of connection points to skip.
|
|
// Returns :
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointEnumerator::Skip(
|
|
ULONG uSkipCount)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
while ((uSkipCount > 0) && (m_iConnectListCurrentPosition != m_lConnectList.end())) {
|
|
m_iConnectListCurrentPosition++;
|
|
uSkipCount--;
|
|
} /* while */
|
|
|
|
return NOERROR;
|
|
} /* CConnectionPointEnumerator::Skip() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::CConnectionPoint()
|
|
// Purpose : Constructor. Initializes variables and adds us
|
|
// to our connection point container.
|
|
// Context : Called at construction time, usually when
|
|
// a server is just initializing.
|
|
// Returns : Nothing.
|
|
// Params :
|
|
// pConnptContainer Pointer to the connection point
|
|
// container which we belong to.
|
|
// riid IID of the interface that
|
|
// this connection point represents.
|
|
// Notes :
|
|
// If AddConnectionPoint() fails, we are dead in the water.
|
|
// We should change this later to throw an exception. FIX.
|
|
*F*/
|
|
CConnectionPoint::CConnectionPoint(
|
|
CConnectionPointContainer *pConnPtContainer,
|
|
IID riid) :
|
|
m_dwCookie(1),
|
|
m_dwRefCount(0),
|
|
m_pContainer(pConnPtContainer),
|
|
m_iIID(riid)
|
|
{
|
|
InitializeCriticalSection(&m_csState);
|
|
CAutoLock l(&m_csState);
|
|
|
|
if (m_pContainer != (CConnectionPointContainer *) NULL) {
|
|
m_pContainer->AddConnectionPoint((IUnknown *) this);
|
|
} /* if */
|
|
} /* CConnectionPoint::CConnectionPoint() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::~CConnectionPoint()
|
|
// Purpose : Destructor.
|
|
// Context : Called at destruction time.
|
|
// Returns : Nothing.
|
|
// Params :
|
|
// Notes :
|
|
*F*/
|
|
CConnectionPoint::~CConnectionPoint()
|
|
{
|
|
EnterCriticalSection(&m_csState);
|
|
// Try to grab the critical section to ensure that nobody else has it.
|
|
LeaveCriticalSection(&m_csState);
|
|
// Can't delete it while we hold it, so release it just before deletion.
|
|
DeleteCriticalSection(&m_csState);
|
|
// Pray for no context switch - as far as I can see, there isn't
|
|
// anything we can do about one occurring. We just have to assert
|
|
// that the application doesn't cause us to be destroyed while still using us.
|
|
} /* CConnectionPoint::~CConnectionPoint() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::SetContainer()
|
|
// Purpose : Allows the connection point container for this cp to be
|
|
// set after construction. Fail if it has been previously set.
|
|
// Context : Called before this connection point is used for
|
|
// anything which involves its container.
|
|
// Returns :
|
|
// NOERROR Successfully recorded container.
|
|
// E_UNEXPECTED Container previously set.
|
|
// E_INVALIDARG Invalid pContainer parameter.
|
|
// Params :
|
|
// pContainer Pointer to the container to use for this cp.
|
|
// Notes :
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPoint::SetContainer(
|
|
CConnectionPointContainer *pContainer)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (IsBadReadPtr((PVOID) pContainer, sizeof(CConnectionPointContainer *))) {
|
|
// Bogus container passed in.
|
|
return E_INVALIDARG;
|
|
} /* if */
|
|
|
|
if (m_pContainer != (CConnectionPointContainer *) NULL) {
|
|
// Connection point container previously set.
|
|
return E_UNEXPECTED;
|
|
} /* if */
|
|
|
|
m_pContainer = pContainer;
|
|
m_pContainer->AddConnectionPoint((IUnknown *) this);
|
|
return NOERROR;
|
|
} /* CConnectionPoint::SetContainer() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::AddRef
|
|
// Purpose : Increment the reference count for this object.
|
|
// Context : Called by any program which wants to ensure
|
|
// that this object isn't destroyed before it
|
|
// says it is done with it (via Release(), below.)
|
|
// Called implicitly when a program successfully
|
|
// calls our QueryInterface() method.
|
|
// Returns : Current number of references held for this
|
|
// object.
|
|
// Params : None.
|
|
// Notes : Standard COM method.
|
|
*F*/
|
|
ULONG
|
|
CConnectionPoint::AddRef() {
|
|
CAutoLock l(&m_csState);
|
|
m_dwRefCount++;
|
|
return m_dwRefCount;
|
|
} /* CConnectionPoint::AddRef() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::Advise
|
|
// Purpose : Add a new sink to this connection point.
|
|
// Context : Called by the application which wishes to
|
|
// receive callbacks from this connection point.
|
|
// We will query the callback interface from the
|
|
// application, AddRef() it, and hand back a cookie.
|
|
// Returns :
|
|
// NOERROR Successfully setup connection
|
|
// E_NOINTERFACE The application doesn't support the
|
|
// interface that we expect to callback into.
|
|
// E_INVALIDARG Bogus pIUnknown or pdwCookie passed in.
|
|
// Params :
|
|
// pIUnknownSink Pointer to an IUnknown of the application.
|
|
// Used to query for the interface we callback into.
|
|
// pdwCookie Out parameter used to hand a cookie back to
|
|
// the app that represents this connection.
|
|
// We put the interator to our list of connections
|
|
// there to allow constant time access during
|
|
// the Unadvise() call that occurs later on.
|
|
// Notes :
|
|
// No need to release pIUnknownSink because its scope
|
|
// is known to be encapsulated for the life of this function,
|
|
// so the called did not addref it before passing it to us.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPoint::Advise(
|
|
IUnknown *pIUnknownSink,
|
|
DWORD *pdwCookie)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
HRESULT hErr;
|
|
|
|
if (IsBadReadPtr((PVOID) pIUnknownSink, sizeof(IUnknown *)) ||
|
|
IsBadWritePtr((PVOID) pdwCookie, sizeof(DWORD))) {
|
|
return E_INVALIDARG;
|
|
} /* if */
|
|
|
|
IUnknown *pIClient;
|
|
hErr = pIUnknownSink->QueryInterface(m_iIID,
|
|
(PVOID *) &pIClient);
|
|
if (FAILED(hErr)) {
|
|
return hErr;
|
|
} /* if */
|
|
|
|
CONNECTDATA sNewConnectData;
|
|
sNewConnectData.pUnk = pIUnknownSink;
|
|
sNewConnectData.dwCookie = m_dwCookie++;
|
|
*pdwCookie = sNewConnectData.dwCookie;
|
|
|
|
m_lConnectList.push_back(sNewConnectData);
|
|
return NOERROR;
|
|
} /* CConnectionPoint::Advise() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::EnumConnections()
|
|
// Purpose : Return an enumerator to look at what connections we have made.
|
|
// Context :
|
|
// Returns :
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// E_OUTOFMEMORY Insufficient memory to create enumerator.
|
|
// Params :
|
|
// ppIEnumConnections Parameter to return enumerator interface pointer in.
|
|
// Notes :
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPoint::EnumConnections(
|
|
IEnumConnections **ppIEnumConnections)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
CConnectionPointEnumerator *pNewConnPtEnum;
|
|
pNewConnPtEnum = new CConnectionPointEnumerator(m_lConnectList, m_lConnectList.begin());
|
|
if (pNewConnPtEnum == (CConnectionPointEnumerator *) NULL) {
|
|
return E_OUTOFMEMORY;
|
|
} /* if */
|
|
|
|
HRESULT hErr;
|
|
hErr = pNewConnPtEnum->QueryInterface(IID_IEnumConnections,
|
|
(PVOID *) ppIEnumConnections);
|
|
if (FAILED(hErr)) {
|
|
delete pNewConnPtEnum;
|
|
} /* if */
|
|
|
|
return hErr;
|
|
} /* CConnectionPoint::EnumConnections() */
|
|
|
|
|
|
/*F*
|
|
// Name :
|
|
// Purpose :
|
|
// Context :
|
|
// Returns :
|
|
// Params :
|
|
// Notes :
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPoint::GetConnectionInterface(
|
|
IID *pIConnection)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
*pIConnection = m_iIID;
|
|
return NOERROR;
|
|
} /* CConnectionPoint::GetConnectionInterface() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::GetConnectionPointContainer()
|
|
// Purpose : Return the connection point container that owns this cp.
|
|
// Context : Called by the app when looking for our container (duh).
|
|
// Returns :
|
|
// E_UNEXPECTED Connection point container for this
|
|
// connection point hasn't been
|
|
// NOERROR Successfully returned the connection point container
|
|
// interface, AddRef()ed.
|
|
// Params :
|
|
// ppIConnPtcontainer Pointer to the connection point container
|
|
// that is to be returned.
|
|
// Notes :
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPoint::GetConnectionPointContainer(
|
|
IConnectionPointContainer **ppIConnPtContainer)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
HRESULT hErr;
|
|
if (m_pContainer != (CConnectionPointContainer *) NULL) {
|
|
// Return an AddRef()ed interface pointer.
|
|
hErr = m_pContainer->QueryInterface(IID_IConnectionPointContainer,
|
|
(PVOID *) ppIConnPtContainer);
|
|
return hErr;
|
|
} else {
|
|
// Our connection point container hasn't been set yet
|
|
// via our constructor or via SetContainer().
|
|
return E_UNEXPECTED;
|
|
} /* if */
|
|
} /* CConnectionPoint::GetConnectionPointContainer() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::QueryInterface
|
|
// Purpose : Query us for our IConnectionPoint interface.
|
|
// Context :
|
|
// Returns : NOERROR if interface successfully found.
|
|
// E_NOINTERFACE otherwise.
|
|
// Params :
|
|
// riid IID of the desired interface
|
|
// ppv Pointer to a VOID * to store the
|
|
// returned interface in.
|
|
// Notes : Implicitly AddRef()s this object on success.
|
|
*F*/
|
|
STDMETHODIMP
|
|
CConnectionPoint::QueryInterface(
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (riid == IID_IConnectionPoint) {
|
|
// Our own interface
|
|
*ppv = (IConnectionPoint *) this;
|
|
} else if (riid == IID_IUnknown) {
|
|
*ppv = (IUnknown *) this;
|
|
} else {
|
|
return E_NOINTERFACE;
|
|
} /* if */
|
|
|
|
AddRef();
|
|
// Implicit AddRef(). The Release() must be explicitly done
|
|
// by the routine that called QueryInterface().
|
|
return NOERROR;
|
|
} /* CConnectionPoint::QueryInterface() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::Release
|
|
// Purpose : Decrement the reference count for this object.
|
|
// Context : Called by any program which holds a reference
|
|
// to this object which no longer needs it.
|
|
// Returns : Current reference count.
|
|
// Params : None.
|
|
// Notes : Should be called once for each AddRef()
|
|
// a program makes and once for each successful
|
|
// QueryInterface() a program made on us.
|
|
*F*/
|
|
ULONG
|
|
CConnectionPoint::Release() {
|
|
EnterCriticalSection(&m_csState);
|
|
m_dwRefCount--;
|
|
if (m_dwRefCount==0) {
|
|
LeaveCriticalSection(&m_csState);
|
|
delete this;
|
|
return 0;
|
|
}
|
|
LeaveCriticalSection(&m_csState);
|
|
return m_dwRefCount;
|
|
} /* CConnectionPoint::Release() */
|
|
|
|
|
|
struct bCookieMatch : public binary_function<CONNECTDATA, DWORD, bool> {
|
|
bool operator()(const CONNECTDATA& connectData, const DWORD& dwCookie) const {
|
|
if (connectData.dwCookie == dwCookie) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
} /* if */
|
|
} /* operator() */
|
|
}; /* bCookieMatch() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPoint::Unadvise()
|
|
// Purpose : The connection sink wishes to break off our mutual
|
|
// connection.
|
|
// Context :
|
|
// Params :
|
|
// dwCookie Cookie to use to find connection to tear down.
|
|
// Returns :
|
|
// NOERROR Connection broken down.
|
|
// CONNECT_E_NOCONNECTION No connection matching dwCookie.
|
|
// Notes :
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPoint::Unadvise(
|
|
DWORD dwCookie)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
list<CONNECTDATA>::iterator iConnectListIterator;
|
|
|
|
int count = m_lConnectList.size();
|
|
|
|
iConnectListIterator = find_if(m_lConnectList.begin(), m_lConnectList.end(),
|
|
bind2nd(bCookieMatch(), dwCookie));
|
|
if (iConnectListIterator != m_lConnectList.end()) {
|
|
// Found the connection we are looking for.
|
|
(*iConnectListIterator).pUnk->Release(); // Release the interface
|
|
m_lConnectList.erase(iConnectListIterator); // Erase the entry
|
|
return NOERROR;
|
|
} else {
|
|
// No connection matching indicated cookie found!
|
|
return CONNECT_E_NOCONNECTION;
|
|
} /* if */
|
|
} /* CConnectionPoint::Unadvise() */
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// Begin CConnectionPointContainerEnumerator
|
|
//
|
|
//
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::AddRef
|
|
// Purpose : Increment the reference count for this object.
|
|
// Context : Called by any program which wants to ensure
|
|
// that this object isn't destroyed before it
|
|
// says it is done with it (via Release(), below.)
|
|
// Called implicitly when a program successfully
|
|
// calls our QueryInterface() method.
|
|
// Returns : Current number of references held for this
|
|
// object.
|
|
// Params : None.
|
|
// Notes : Standard COM method.
|
|
*F*/
|
|
ULONG
|
|
CConnectionPointContainerEnumerator::AddRef() {
|
|
CAutoLock l(&m_csState);
|
|
m_pIUnknownParent->AddRef(); // Per BS Pg. 208
|
|
m_dwRefCount++;
|
|
return m_dwRefCount;
|
|
} /* CConnectionPointContainerEnumerator::AddRef() */
|
|
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::CConnectionPointContainerEnumerator
|
|
// Purpose : Constructor. Stores which connection point we are pointing at.
|
|
// Context : Called when this object is created.
|
|
// Returns :
|
|
// Params :
|
|
// iConnPointNumber Integer which indicates which connection point
|
|
// this enumerator is currently pointing at.
|
|
// Notes : None.
|
|
*F*/
|
|
CConnectionPointContainerEnumerator::CConnectionPointContainerEnumerator(
|
|
IUnknown *pIUnknownParent,
|
|
IConnectionPointList_t IConnectionPointList,
|
|
IConnectionPointList_t::iterator iConnectionPointListPosition)
|
|
{
|
|
InitializeCriticalSection(&m_csState);
|
|
CAutoLock l(&m_csState);
|
|
m_dwRefCount = 0;
|
|
|
|
// Store these in our member variables.
|
|
m_IConnectionPointList = IConnectionPointList;
|
|
m_iConnectionPointListPosition = iConnectionPointListPosition;
|
|
m_pIUnknownParent = pIUnknownParent;
|
|
|
|
// Addref() all of our connection points.
|
|
IConnectionPointList_t::iterator iConnPtIterator;
|
|
for (iConnPtIterator = m_IConnectionPointList.begin();
|
|
iConnPtIterator != m_IConnectionPointList.end();
|
|
iConnPtIterator++) {
|
|
(*iConnPtIterator)->AddRef();
|
|
} /* for */
|
|
pIUnknownParent->AddRef();
|
|
} /* CConnectionPointContainerEnumerator::CConnectionPointContainerEnumerator() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::~CConnectionPointContainerEnumerator
|
|
// Purpose : Destructor.
|
|
// Context : Called when this object is destroyed.
|
|
// Returns :
|
|
// Params :
|
|
// Notes : None.
|
|
*F*/
|
|
CConnectionPointContainerEnumerator::~CConnectionPointContainerEnumerator(void)
|
|
{
|
|
EnterCriticalSection(&m_csState);
|
|
|
|
// Release() all of our connection points.
|
|
IConnectionPointList_t::iterator iConnPtIterator;
|
|
for (iConnPtIterator = m_IConnectionPointList.begin();
|
|
iConnPtIterator != m_IConnectionPointList.end();
|
|
iConnPtIterator++) {
|
|
(*iConnPtIterator)->Release();
|
|
} /* for */
|
|
|
|
DeleteCriticalSection(&m_csState);
|
|
} /* CConnectionPointContainerEnumerator::~CConnectionPointContainerEnumerator() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::Clone
|
|
// Purpose : Return an identical enumerator pointing at the same
|
|
// point in our list of connection points.
|
|
// Context :
|
|
// Returns :
|
|
// Params :
|
|
// E_OUTOFMEMORY Insufficient memory to create new enumerator.
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainerEnumerator::Clone(
|
|
IEnumConnectionPoints **ppIEnumConnPoints)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
CConnectionPointContainerEnumerator *pNewConnPtContainerEnum;
|
|
pNewConnPtContainerEnum = new CConnectionPointContainerEnumerator((IUnknown *) this,
|
|
m_IConnectionPointList,
|
|
m_iConnectionPointListPosition);
|
|
if (pNewConnPtContainerEnum == (CConnectionPointContainerEnumerator *) NULL) {
|
|
return E_OUTOFMEMORY;
|
|
} /* if */
|
|
|
|
HRESULT hErr;
|
|
hErr = pNewConnPtContainerEnum->QueryInterface(IID_IEnumConnectionPoints,
|
|
(PVOID *) ppIEnumConnPoints);
|
|
if (FAILED(hErr)) {
|
|
delete pNewConnPtContainerEnum;
|
|
} /* if */
|
|
|
|
return hErr;
|
|
} /* CConnectionPointContainerEnumerator::Clone() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::Next
|
|
// Purpose :
|
|
// Context :
|
|
// Params :
|
|
// E_POINTER Invalid ppCPArray parameter passed in.
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// Returns :
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainerEnumerator::Next(
|
|
ULONG uPointsToReturn,
|
|
IConnectionPoint **ppCPArray,
|
|
ULONG *puPointsReturned)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (IsBadWritePtr(ppCPArray, uPointsToReturn * sizeof(IConnectionPoint *))) {
|
|
return E_POINTER;
|
|
} /* if */
|
|
|
|
*puPointsReturned = 0;
|
|
HRESULT hErr;
|
|
while ((uPointsToReturn > 0) &&
|
|
(m_iConnectionPointListPosition != m_IConnectionPointList.end())) {
|
|
hErr = (*m_iConnectionPointListPosition)->QueryInterface(IID_IConnectionPoint,
|
|
(PVOID *) ppCPArray);
|
|
if (SUCCEEDED(hErr)) {
|
|
ppCPArray++;
|
|
(*puPointsReturned)++;
|
|
uPointsToReturn--;
|
|
}/* if */
|
|
m_iConnectionPointListPosition++;
|
|
} /* while */
|
|
|
|
return NOERROR;
|
|
} /* CConnectionPointContainerEnumerator::Next() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::QueryInterface
|
|
// Purpose : Query us for an interface.
|
|
// Context :
|
|
// Returns : NOERROR if interface successfully found.
|
|
// E_NOINTERFACE otherwise.
|
|
// Params :
|
|
// riid IID of the desired interface
|
|
// ppv Pointer to a VOID * to store the
|
|
// returned interface in.
|
|
// Notes : Implicitly AddRef()s this object on success.
|
|
*F*/
|
|
STDMETHODIMP
|
|
CConnectionPointContainerEnumerator::QueryInterface(
|
|
REFIID riid,
|
|
void **ppv)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (riid == IID_IEnumConnectionPoints) {
|
|
// Our own interface
|
|
*ppv = (IEnumConnectionPoints *) this;
|
|
} else if (riid == IID_IUnknown) {
|
|
*ppv = (IUnknown *) this;
|
|
} else {
|
|
return E_NOINTERFACE;
|
|
} /* if */
|
|
|
|
AddRef();
|
|
// Implicit AddRef(). The Release() must be explicitly done
|
|
// by the routine that called QueryInterface().
|
|
return NOERROR;
|
|
} /* CConnectionPointContainerEnumerator::QueryInterface() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::Release
|
|
// Purpose : Decrement the reference count for this object.
|
|
// Context : Called by any program which holds a reference
|
|
// to this object which no longer needs it.
|
|
// Returns : Current reference count.
|
|
// Params : None.
|
|
// Notes : Should be called once for each AddRef()
|
|
// a program makes and once for each successful
|
|
// QueryInterface() a program made on us.
|
|
*F*/
|
|
ULONG
|
|
CConnectionPointContainerEnumerator::Release() {
|
|
EnterCriticalSection(&m_csState);
|
|
m_pIUnknownParent->Release(); // Per BS pg.208
|
|
m_dwRefCount--;
|
|
|
|
if (m_dwRefCount==0) {
|
|
LeaveCriticalSection(&m_csState);
|
|
delete this;
|
|
return 0;
|
|
}
|
|
LeaveCriticalSection(&m_csState);
|
|
return m_dwRefCount;
|
|
} /* CConnectionPointContainerEnumerator::Release() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::Reset
|
|
// Purpose : Start the enumerator at the beginning of the
|
|
// connection point list again.
|
|
// Context : Any point after construction.
|
|
// Returns :
|
|
// NOERROR Successfully reset enumerator.
|
|
// Params : None.
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainerEnumerator::Reset(void)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
m_iConnectionPointListPosition = m_IConnectionPointList.begin();
|
|
return NOERROR;
|
|
} /* CConnectionPointContainerEnumerator::Reset() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainerEnumerator::Skip
|
|
// Purpose : Skip forward over the specified number of connection points.
|
|
// Context :
|
|
// Params :
|
|
// uSkipCount Number of connection points to skip.
|
|
// Returns :
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainerEnumerator::Skip(
|
|
ULONG uSkipCount)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
while ((uSkipCount > 0) &&
|
|
(m_iConnectionPointListPosition != m_IConnectionPointList.end())) {
|
|
m_iConnectionPointListPosition++;
|
|
uSkipCount--;
|
|
} /* while */
|
|
|
|
return NOERROR;
|
|
} /* CConnectionPointContainerEnumerator::Skip() */
|
|
|
|
|
|
//
|
|
//
|
|
// Begin CConnectionPointContainer
|
|
//
|
|
//
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainer::CConnectionPointContainer
|
|
// Purpose : Constructor. Doesn't do much.
|
|
// Context : Called when this object is created.
|
|
// Returns :
|
|
// Params :
|
|
// pParentUnknown IUnknown for the parent of this container
|
|
// so that we can pass QIs and such to it.
|
|
// Notes : None.
|
|
*F*/
|
|
CConnectionPointContainer::CConnectionPointContainer() :
|
|
m_pIParentUnknown((IUnknown *) NULL)
|
|
{
|
|
InitializeCriticalSection(&m_csState);
|
|
CAutoLock l(&m_csState);
|
|
} /* CConnectionPointContainer::CConnectionPointContainer() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainer::~CConnectionPointContainer()
|
|
// Purpose :
|
|
// Context :
|
|
// Returns :
|
|
// Params : None.
|
|
// Notes : None.
|
|
*F*/
|
|
CConnectionPointContainer::~CConnectionPointContainer()
|
|
{
|
|
IConnectionPointList_t::iterator iConnPtListIterator;
|
|
EnterCriticalSection(&m_csState);
|
|
|
|
while (m_lConnectionPointList.begin() != m_lConnectionPointList.end()) {
|
|
iConnPtListIterator = m_lConnectionPointList.begin();
|
|
(*iConnPtListIterator)->Release();
|
|
m_lConnectionPointList.erase(iConnPtListIterator);
|
|
} /* if */
|
|
LeaveCriticalSection(&m_csState);
|
|
DeleteCriticalSection(&m_csState);
|
|
} /* CConnectionPointContainer::~CConnectionPointContainer() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainer::SetUnknown()
|
|
// Purpose : Store the IUnknown of the parent in order
|
|
// to delegate IUnknown calls to it. We are
|
|
// merely a helper class, not a true COM object.
|
|
// Context :
|
|
// Returns :
|
|
// E_UNEXPECTED Parent IUnknown previously set.
|
|
// NOERROR Successfully recorded parent IUnknown.
|
|
// Params : None.
|
|
// Notes :
|
|
// pIParentUnknown Pointer to the IUnknown of the parent
|
|
// which we are supposed to delegate to.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainer::SetUnknown(
|
|
IUnknown *pIParentUnknown)
|
|
{
|
|
if (m_pIParentUnknown != (IUnknown *) NULL) {
|
|
// Parent unknown previously set.
|
|
return E_UNEXPECTED;
|
|
} /* if */
|
|
|
|
m_pIParentUnknown = pIParentUnknown;
|
|
return NOERROR;
|
|
} /* CConnectionPointContainer::SetUnknown() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainer::EnumConnectionPoints
|
|
// Purpose : Create a connection point container enumerator
|
|
// and return it to the callind program.
|
|
// Context : Called when a program wants to enumerate through
|
|
// the list of connection points we support.
|
|
// Returns :
|
|
// E_OUTOFMEMORY Insufficient memory to create new enumerator.
|
|
// NOERROR Successfully created & returned enumerator.
|
|
// Params : None.
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainer::EnumConnectionPoints(
|
|
IEnumConnectionPoints **ppIEnumConnPoints)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
CConnectionPointContainerEnumerator *pNewConnPtContainerEnum;
|
|
pNewConnPtContainerEnum = new CConnectionPointContainerEnumerator((IUnknown *) this,
|
|
m_lConnectionPointList,
|
|
m_lConnectionPointList.begin());
|
|
if (pNewConnPtContainerEnum == (CConnectionPointContainerEnumerator *) NULL) {
|
|
return E_OUTOFMEMORY;
|
|
} /* if */
|
|
|
|
HRESULT hErr;
|
|
hErr = pNewConnPtContainerEnum->QueryInterface(IID_IEnumConnectionPoints,
|
|
(PVOID *) ppIEnumConnPoints);
|
|
if (FAILED(hErr)) {
|
|
delete pNewConnPtContainerEnum;
|
|
} /* if */
|
|
|
|
return hErr;
|
|
} /* CConnectionPointContainer::EnumConnectionPoints() */
|
|
|
|
|
|
struct bIIDMatch : public binary_function<IConnectionPoint *, IID, bool> {
|
|
bool operator()(IConnectionPoint *pICP, const IID riid) const {
|
|
IID sIConnection;
|
|
HRESULT hErr = pICP->GetConnectionInterface(&sIConnection);
|
|
if (FAILED(hErr)) {
|
|
// Error with this connection point.
|
|
return FALSE;
|
|
} /* if */
|
|
if (sIConnection == riid) {
|
|
// This connection point exposes the requested interface.
|
|
return TRUE;
|
|
} else {
|
|
// This connection point does not expose the requested interface.
|
|
return FALSE;
|
|
} /* if */
|
|
} /* operator() */
|
|
}; /* bIIDMatch() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainer::FindConnectionPoint
|
|
// Purpose : Check if this connection point container supports
|
|
// a particular connection point.
|
|
// Context :
|
|
// Returns :
|
|
// E_POINTER Invalid ppIConnectionPoint parameter passed in.
|
|
// CONNECT_E_NOCONNECTION No connection point matching indicated REFIID.
|
|
// NOERROR Successfully returned AddRef()ed connection point.
|
|
// Params :
|
|
// rConnPointIID IID of the desired connection point.
|
|
// ppIConnectionPoint Indirect pointer to return connection
|
|
// point matching rConnPointIID (if found.)
|
|
// Notes : None.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainer::FindConnectionPoint(
|
|
REFIID rConnPointIID,
|
|
IConnectionPoint **ppIConnectionPoint)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (IsBadWritePtr(ppIConnectionPoint, sizeof(IConnectionPoint *))) {
|
|
return E_POINTER;
|
|
} /* if */
|
|
|
|
IConnectionPointList_t::iterator iConnPtListIterator;
|
|
iConnPtListIterator = find_if(m_lConnectionPointList.begin(), m_lConnectionPointList.end(),
|
|
bind2nd(bIIDMatch(), rConnPointIID));
|
|
|
|
if (iConnPtListIterator != m_lConnectionPointList.end()) {
|
|
// Found the connection point matching the indicated IID.
|
|
*ppIConnectionPoint = *iConnPtListIterator;
|
|
(*ppIConnectionPoint)->AddRef();
|
|
return NOERROR;
|
|
} else {
|
|
// No connection point matches the requested IID.
|
|
return CONNECT_E_NOCONNECTION;
|
|
} /* if */
|
|
} /* CConnectionPointContainer::FindConnectionPoint() */
|
|
|
|
|
|
/*F*
|
|
// Name : CConnectionPointContainer::AddConnectionPoint
|
|
// Purpose : Class method used to allow parent object to
|
|
// add connection points to this connection point container.
|
|
// Context :
|
|
// Returns :
|
|
// E_POINTER Invalid pINewConnectionPoint parameter.
|
|
// NOERROR Successfully added connection point to our list.
|
|
// Also returns error codes returned by QueryInterface()/
|
|
// Params :
|
|
// pIUnknownNewConnectionPoint IUnknown of the new connection point.
|
|
// Notes :
|
|
// All connection points should be added before any calls to
|
|
// the IConnectionPointContainer interface are made.
|
|
*F*/
|
|
HRESULT
|
|
CConnectionPointContainer::AddConnectionPoint(
|
|
IUnknown *pIUnknownNewConnectionPoint)
|
|
{
|
|
CAutoLock l(&m_csState);
|
|
if (IsBadReadPtr((PVOID) pIUnknownNewConnectionPoint, sizeof(IConnectionPoint *))) {
|
|
return E_POINTER;
|
|
} /* if */
|
|
|
|
HRESULT hErr;
|
|
IConnectionPoint *pINewConnectionPoint;
|
|
hErr = pIUnknownNewConnectionPoint->QueryInterface(IID_IConnectionPoint,
|
|
(PVOID *) &pINewConnectionPoint);
|
|
if (FAILED(hErr)) {
|
|
return hErr;
|
|
} /* if */
|
|
|
|
m_lConnectionPointList.push_back(pINewConnectionPoint);
|
|
return NOERROR;
|
|
} /* CConnectionPointContainer::AddConnectionPoint() */
|
|
|
|
|
|
#endif _CONNECT_CPP_
|