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.
1051 lines
25 KiB
1051 lines
25 KiB
//***************************************************************************
|
|
//
|
|
// File:
|
|
//
|
|
// Module: MS SNMP Provider
|
|
//
|
|
// Purpose:
|
|
//
|
|
// Copyright (c) 1997-2002 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
/*
|
|
* SMIREVT.CPP
|
|
*
|
|
* Implemenation of a connection point object for the SMIR notify mechanism.
|
|
* The methods/objects in this file are accessed by the SMIR API; the API
|
|
* provides a user friendly interface to ISMIRNotify.
|
|
*/
|
|
#include <precomp.h>
|
|
#include "csmir.h"
|
|
#include "smir.h"
|
|
#include "handles.h"
|
|
#include "classfac.h"
|
|
#include <textdef.h>
|
|
#include "evtcons.h"
|
|
#ifdef ICECAP_PROFILE
|
|
#include <icapexp.h>
|
|
#endif
|
|
|
|
// scope guard
|
|
#include <autoptr.h>
|
|
|
|
extern CRITICAL_SECTION g_CriticalSection ;
|
|
|
|
|
|
/**********************************************************************************
|
|
* CSmirConnectionPoint
|
|
*
|
|
* Connectpoint implementation that supports the interface ISMIRNotify.
|
|
*
|
|
* CSmirConnObject::CSmirConnObject
|
|
* CSmirConnObject::~CSmirConnObject
|
|
***********************************************************************************/
|
|
/*
|
|
* CSmirConnectionPoint::CSmirConnectionPoint
|
|
* CSmirConnectionPoint::~CSmirConnectionPoint
|
|
*
|
|
* Parameters (Constructor):
|
|
* pObj PCSmirConnObject of the object we're in. We can
|
|
* query this for the IConnectionPointContainer
|
|
* interface we might need.
|
|
* riid REFIID of the interface we're supporting
|
|
***********************************************************************************/
|
|
|
|
CSmirConnectionPoint::CSmirConnectionPoint(PCSmirConnObject pObj, REFIID riid, CSmir *pSmir)
|
|
{
|
|
m_cRef=0;
|
|
m_iid=riid;
|
|
/*
|
|
* Our lifetime is controlled by the connectable object itself,
|
|
* although other external clients will call AddRef and Release.
|
|
* Since we're nested in the connectable object's lifetime,
|
|
* there's no need to call AddRef on pObj.
|
|
*/
|
|
m_pObj=pObj;
|
|
m_dwCookieNext=100; //Arbitrary starting cookie value
|
|
}
|
|
|
|
CSmirConnectionPoint::~CSmirConnectionPoint(void)
|
|
{
|
|
DWORD lKey = 0;
|
|
LPUNKNOWN pItem = NULL;
|
|
POSITION rNextPosition;
|
|
for(rNextPosition=m_Connections.GetStartPosition();NULL!=rNextPosition;)
|
|
{
|
|
m_Connections.GetNextAssoc(rNextPosition, lKey, pItem );
|
|
pItem->Release();
|
|
}
|
|
m_Connections.RemoveAll();
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnectionPoint::QueryInterface
|
|
* CSmirConnectionPoint::AddRef
|
|
* CSmirConnectionPoint::Release
|
|
*
|
|
* Purpose:
|
|
* Non-delegating IUnknown members for CSmirConnectionPoint.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnectionPoint::QueryInterface(REFIID riid
|
|
, LPVOID *ppv)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
if ((IID_IUnknown == riid) ||
|
|
(IID_IConnectionPoint == riid)||
|
|
(IID_ISMIR_Notify == riid))
|
|
*ppv=(LPVOID)this;
|
|
|
|
if (NULL!=*ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CSmirConnectionPoint::AddRef(void)
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CSmirConnectionPoint::Release(void)
|
|
{
|
|
long ret;
|
|
if (0!=(ret=InterlockedDecrement(&m_cRef)))
|
|
return ret;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnectionPoint::GetConnectionInterface
|
|
*
|
|
* Purpose:
|
|
* Returns the IID of the outgoing interface supported through
|
|
* this connection point.
|
|
*
|
|
* Parameters:
|
|
* pIID IID * in which to store the IID.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnectionPoint::GetConnectionInterface(IID *pIID)
|
|
{
|
|
if (NULL==pIID)
|
|
return ResultFromScode(E_POINTER);
|
|
|
|
*pIID=m_iid;
|
|
return NOERROR;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnectionPoint::GetConnectionPointContainer
|
|
*
|
|
* Purpose:
|
|
* Returns a pointer to the IConnectionPointContainer that
|
|
* is manageing this connection point.
|
|
*
|
|
* Parameters:
|
|
* ppCPC IConnectionPointContainer ** in which to return
|
|
* the pointer after calling AddRef.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnectionPoint::GetConnectionPointContainer
|
|
(IConnectionPointContainer **ppCPC)
|
|
{
|
|
return m_pObj->QueryInterface(IID_IConnectionPointContainer
|
|
, (void **)ppCPC);
|
|
}
|
|
|
|
/*
|
|
* CSmirConnectionPoint::Advise
|
|
*
|
|
* Purpose:
|
|
* Provides this connection point with a notification sink to
|
|
* call whenever the appropriate outgoing function/event occurs.
|
|
*
|
|
* Parameters:
|
|
* pUnkSink LPUNKNOWN to the sink to notify. The connection
|
|
* point must QueryInterface on this pointer to obtain
|
|
* the proper interface to call. The connection
|
|
* point must also insure that any pointer held has
|
|
* a reference count (QueryInterface will do it).
|
|
* pdwCookie DWORD * in which to store the connection key for
|
|
* later calls to Unadvise.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnectionPoint::Advise(LPUNKNOWN pUnkSink
|
|
, DWORD *pdwCookie)
|
|
{
|
|
*pdwCookie=0;
|
|
if (NULL == pUnkSink)
|
|
return E_POINTER;
|
|
|
|
/*
|
|
* Verify that the sink has the interface it's supposed
|
|
* to. We don't have to know what it is because we have
|
|
* m_iid to describe it. If this works, then we
|
|
* have a pointer with an AddRef that we can save.
|
|
*/
|
|
IUnknown *pSink = NULL ;
|
|
if (FAILED(pUnkSink->QueryInterface(m_iid, (PPVOID)&pSink)))
|
|
{
|
|
return CONNECT_E_CANNOTCONNECT;
|
|
}
|
|
|
|
//We got the sink, now store it.
|
|
*pdwCookie = InterlockedIncrement(&m_dwCookieNext);
|
|
|
|
m_Connections.SetAt(*pdwCookie,pSink);
|
|
/*Add ref the smir to make sure that this stays in memory for the lifetime of the
|
|
*sink. The release is in unadvise.
|
|
*/
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnectionPoint::Unadvise
|
|
*
|
|
* Purpose:
|
|
* Terminates the connection to the notification sink identified
|
|
* with dwCookie (that was returned from Advise). The connection
|
|
* point has to Release any held pointers for that sink.
|
|
*
|
|
* Parameters:
|
|
* dwCookie DWORD connection key from Advise.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnectionPoint::Unadvise(DWORD dwCookie)
|
|
{
|
|
//the only invalid cookie is 0
|
|
if (0==dwCookie)
|
|
{
|
|
//MyTraceEvent.Generate(__FILE__,__LINE__, "CSmirConnectionPoint::Unadvise E_INVALIDARG");
|
|
return E_UNEXPECTED;
|
|
}
|
|
LPUNKNOWN pSink = NULL;
|
|
//stop anyone else unadvising with the same cookie
|
|
criticalSection.Lock () ;
|
|
if(TRUE == m_Connections.Lookup(dwCookie,pSink))
|
|
{
|
|
m_Connections.RemoveKey(dwCookie);
|
|
//having removed the key the look up will fail so we can release the critical section
|
|
criticalSection.Unlock () ;
|
|
pSink->Release();
|
|
/*release the smir. This could cause the smir to unload from memory! Do not do
|
|
*anything after this because we are (ultimatly) owned by the smir object
|
|
*/
|
|
|
|
return S_OK;
|
|
}
|
|
criticalSection.Unlock () ;
|
|
return CONNECT_E_NOCONNECTION;
|
|
}
|
|
/*
|
|
* CSmirConnectionPoint::EnumConnections
|
|
*
|
|
* Purpose:
|
|
* Creates and returns an enumerator object with the
|
|
* IEnumConnections interface that will enumerate the IUnknown
|
|
* pointers of each connected sink.
|
|
*
|
|
* Parameters:
|
|
* ppEnum LPENUMCONNECTIONS in which to store the
|
|
* IEnumConnections pointer.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnectionPoint::EnumConnections(LPENUMCONNECTIONS *ppEnum)
|
|
{
|
|
LPCONNECTDATA pCD = NULL;
|
|
PCEnumConnections pEnum = NULL;
|
|
|
|
//NULL the IN parameter
|
|
*ppEnum=NULL;
|
|
|
|
//check that we have some connections
|
|
if (0 == m_Connections.GetCount())
|
|
return ResultFromScode(OLE_E_NOCONNECTION);
|
|
|
|
/*
|
|
* Create the array of CONNECTDATA structures to give to the
|
|
* enumerator.
|
|
*/
|
|
pCD=new CONNECTDATA[(UINT)m_Connections.GetCount()];
|
|
|
|
if (NULL==pCD)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
wmilib::auto_buffer<CONNECTDATA> pCD_Guard ( pCD ) ;
|
|
|
|
DWORD lKey = 0;
|
|
LPUNKNOWN pItem = NULL;
|
|
POSITION rNextPosition;
|
|
UINT j=0;
|
|
for(rNextPosition=m_Connections.GetStartPosition();NULL!=rNextPosition;j++)
|
|
{
|
|
m_Connections.GetNextAssoc(rNextPosition, lKey, pItem );
|
|
pCD[j].pUnk=pItem;
|
|
pCD[j].dwCookie=lKey;
|
|
}
|
|
/*
|
|
* If creation works, it makes a copy pCD, so we can
|
|
* always delete it regardless of the outcome.
|
|
*/
|
|
pEnum=new CEnumConnections(this, m_Connections.GetCount(), pCD);
|
|
|
|
if (NULL==pEnum)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
//This does an AddRef for us.
|
|
return pEnum->QueryInterface(IID_IEnumConnections, (PPVOID)ppEnum);
|
|
}
|
|
|
|
//Connection Enumerator follows
|
|
|
|
/*
|
|
* CEnumConnections::CEnumConnections
|
|
* CEnumConnections::~CEnumConnections
|
|
*
|
|
* Parameters (Constructor):
|
|
* pUnkRef LPUNKNOWN to use for reference counting.
|
|
* cConn ULONG number of connections in prgpConn
|
|
* prgConnData LPCONNECTDATA to the array to enumerate.
|
|
*/
|
|
|
|
CEnumConnections::CEnumConnections(LPUNKNOWN pUnkRef, ULONG cConn
|
|
, LPCONNECTDATA prgConnData) : m_rgConnData ( NULL )
|
|
{
|
|
UINT i;
|
|
|
|
m_cRef=0;
|
|
m_pUnkRef=pUnkRef;
|
|
|
|
m_iCur=0;
|
|
m_cConn=cConn;
|
|
|
|
/*
|
|
* Copy the passed array. We need to do this because a clone
|
|
* has to have its own copy as well.
|
|
*/
|
|
m_rgConnData=new CONNECTDATA[(UINT)cConn];
|
|
|
|
if (NULL!=m_rgConnData)
|
|
{
|
|
for (i=0; i < cConn; i++)
|
|
{
|
|
m_rgConnData[i]=prgConnData[i];
|
|
m_rgConnData[i].pUnk=prgConnData[i].pUnk;
|
|
m_rgConnData[i].pUnk->AddRef();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
CEnumConnections::~CEnumConnections(void)
|
|
{
|
|
if (NULL!=m_rgConnData)
|
|
{
|
|
UINT i;
|
|
|
|
for (i=0; i < m_cConn; i++)
|
|
m_rgConnData[i].pUnk->Release();
|
|
|
|
delete [] m_rgConnData;
|
|
}
|
|
|
|
return;
|
|
}
|
|
/*
|
|
* CEnumConnections::QueryInterface
|
|
* CEnumConnections::AddRef
|
|
* CEnumConnections::Release
|
|
*
|
|
* Purpose:
|
|
* IUnknown members for CEnumConnections object.
|
|
*/
|
|
|
|
STDMETHODIMP CEnumConnections::QueryInterface(REFIID riid
|
|
, LPVOID *ppv)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
if (IID_IUnknown==riid || IID_IEnumConnections==riid)
|
|
*ppv=(LPVOID)this;
|
|
|
|
if (NULL!=*ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CEnumConnections::AddRef(void)
|
|
{
|
|
InterlockedIncrement(&m_cRef);
|
|
m_pUnkRef->AddRef();
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CEnumConnections::Release(void)
|
|
{
|
|
m_pUnkRef->Release();
|
|
|
|
long ret;
|
|
if (0L!=(ret=InterlockedDecrement(&m_cRef)))
|
|
return ret;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CEnumConnections::Next
|
|
*
|
|
* Purpose:
|
|
* Returns the next element in the enumeration.
|
|
*
|
|
* Parameters:
|
|
* cConn ULONG number of connections to return.
|
|
* pConnData LPCONNECTDATA in which to store the returned
|
|
* structures.
|
|
* pulEnum ULONG * in which to return how many we
|
|
* enumerated.
|
|
*
|
|
* Return Value:
|
|
* HRESULT NOERROR if successful, S_FALSE otherwise,
|
|
*/
|
|
|
|
STDMETHODIMP CEnumConnections::Next(ULONG cConn
|
|
, LPCONNECTDATA pConnData, ULONG *pulEnum)
|
|
{
|
|
ULONG cReturn=0L;
|
|
|
|
if (NULL==m_rgConnData)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
if (NULL==pulEnum)
|
|
{
|
|
if (1L!=cConn)
|
|
return ResultFromScode(E_POINTER);
|
|
}
|
|
else
|
|
*pulEnum=0L;
|
|
|
|
if (NULL==pConnData || m_iCur >= m_cConn)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
while (m_iCur < m_cConn && cConn > 0)
|
|
{
|
|
*pConnData++=m_rgConnData[m_iCur];
|
|
m_rgConnData[m_iCur++].pUnk->AddRef();
|
|
cReturn++;
|
|
cConn--;
|
|
}
|
|
|
|
if (NULL!=pulEnum)
|
|
*pulEnum=cReturn;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CEnumConnections::Skip(ULONG cSkip)
|
|
{
|
|
if (((m_iCur+cSkip) >= m_cConn) || NULL==m_rgConnData)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
m_iCur+=cSkip;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CEnumConnections::Reset(void)
|
|
{
|
|
m_iCur=0;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CEnumConnections::Clone(LPENUMCONNECTIONS *ppEnum)
|
|
{
|
|
PCEnumConnections pNew;
|
|
|
|
*ppEnum=NULL;
|
|
|
|
//Create the clone
|
|
pNew=new CEnumConnections(m_pUnkRef, m_cConn, m_rgConnData);
|
|
|
|
if (NULL==pNew)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
pNew->AddRef();
|
|
pNew->m_iCur=m_iCur;
|
|
|
|
*ppEnum=pNew;
|
|
return NOERROR;
|
|
}
|
|
|
|
/**********************************************************************************
|
|
* CSmirConnObject
|
|
*
|
|
* Connectable Object implementation that supports the
|
|
* interface ISMIRNotify.
|
|
*
|
|
* CSmirConnObject::CSmirConnObject
|
|
* CSmirConnObject::~CSmirConnObject
|
|
***********************************************************************************/
|
|
|
|
CSmirConnObject::CSmirConnObject(CSmir *pSmir) : m_rgpConnPt ( NULL )
|
|
{
|
|
// CSMIRClassFactory::objectsInProgress++;
|
|
m_cRef=0;
|
|
//create SMIR_NUMBER_OF_CONNECTION_POINTS connection points
|
|
m_rgpConnPt = new CSmirConnectionPoint*[SMIR_NUMBER_OF_CONNECTION_POINTS];
|
|
for(int iLoop=0;iLoop<SMIR_NUMBER_OF_CONNECTION_POINTS;iLoop++)
|
|
m_rgpConnPt[iLoop] = NULL;
|
|
|
|
try
|
|
{
|
|
Init(pSmir);
|
|
}
|
|
catch(...)
|
|
{
|
|
if (m_rgpConnPt)
|
|
{
|
|
//free the connection points
|
|
for(int iLoop=0;iLoop<SMIR_NUMBER_OF_CONNECTION_POINTS;iLoop++)
|
|
{
|
|
if (NULL!=m_rgpConnPt[iLoop])
|
|
{
|
|
//release all of the connected objects
|
|
//while(m_rgpConnPt[iLoop]->Release());
|
|
m_rgpConnPt[iLoop]->Release();
|
|
}
|
|
}
|
|
//and delete the connection point
|
|
delete[] m_rgpConnPt;
|
|
m_rgpConnPt = NULL;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
CSmirConnObject::~CSmirConnObject(void)
|
|
{
|
|
if (m_rgpConnPt)
|
|
{
|
|
//free the connection points
|
|
for(int iLoop=0;iLoop<SMIR_NUMBER_OF_CONNECTION_POINTS;iLoop++)
|
|
{
|
|
if (NULL!=m_rgpConnPt[iLoop])
|
|
{
|
|
//release all of the connected objects
|
|
//while(m_rgpConnPt[iLoop]->Release());
|
|
m_rgpConnPt[iLoop]->Release();
|
|
}
|
|
}
|
|
//and delete the connection point
|
|
delete[] m_rgpConnPt;
|
|
}
|
|
|
|
// CSMIRClassFactory::objectsInProgress--;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnObject::Init
|
|
*
|
|
* Purpose:
|
|
* Instantiates the interface implementations for this object.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Return Value:
|
|
* BOOL TRUE if initialization succeeds, FALSE otherwise.
|
|
*/
|
|
|
|
BOOL CSmirConnObject::Init(CSmir *pSmir)
|
|
{
|
|
//Create our connection points
|
|
|
|
//the smir change CP
|
|
m_rgpConnPt[SMIR_NOTIFY_CONNECTION_POINT]=
|
|
new CSmirNotifyCP(this,
|
|
IID_ISMIR_Notify, pSmir);
|
|
|
|
if (NULL==m_rgpConnPt[SMIR_NOTIFY_CONNECTION_POINT])
|
|
return FALSE;
|
|
|
|
m_rgpConnPt[SMIR_NOTIFY_CONNECTION_POINT]->AddRef();
|
|
|
|
return TRUE;
|
|
}
|
|
/*
|
|
* CSmirConnObject::QueryInterface
|
|
*
|
|
* Purpose:
|
|
* Manages the interfaces for this object which supports the
|
|
* IUnknown, ISampleOne, and ISampleTwo interfaces.
|
|
*
|
|
* Parameters:
|
|
* riid REFIID of the interface to return.
|
|
* ppv PPVOID in which to store the pointer.
|
|
*
|
|
* Return Value:
|
|
* HRESULT NOERROR on success, E_NOINTERFACE if the
|
|
* interface is not supported.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnObject::QueryInterface(REFIID riid, PPVOID ppv)
|
|
{
|
|
if (ppv)
|
|
*ppv = NULL;
|
|
else
|
|
return E_INVALIDARG;
|
|
|
|
if((IID_IConnectionPointContainer == riid)||(IID_ISMIR_Notify == riid))
|
|
*ppv = this;
|
|
else
|
|
return E_NOINTERFACE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnObject::AddRef
|
|
* CSmirConnObject::Release
|
|
*
|
|
* Reference counting members. When Release sees a zero count
|
|
* the object destroys itself.
|
|
*/
|
|
|
|
DWORD CSmirConnObject::AddRef(void)
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
DWORD CSmirConnObject::Release(void)
|
|
{
|
|
long ret;
|
|
if (0!=(ret=InterlockedDecrement(&m_cRef)))
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnObject::EnumConnectionPoints
|
|
*
|
|
* Purpose:
|
|
* Creates and returns an enumerator object with the
|
|
* IEnumConnectionPoints interface that will enumerate the
|
|
* individual connection points supported in this object.
|
|
*
|
|
* Parameters:
|
|
* ppEnum LPENUMCONNECTIONPOINTS in which to store the
|
|
* IEnumConnectionPoints pointer.
|
|
*
|
|
* Return Value:
|
|
* HRESULT NOERROR on success, E_OUTOFMEMORY on failure or
|
|
* other error code.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnObject :: EnumConnectionPoints
|
|
(LPENUMCONNECTIONPOINTS *ppEnum)
|
|
{
|
|
IConnectionPoint **rgCP = NULL ;
|
|
CEnumConnectionPoints * pEnum = NULL ;
|
|
|
|
*ppEnum=NULL;
|
|
|
|
rgCP=(IConnectionPoint **)m_rgpConnPt;
|
|
|
|
//Create the enumerator: we have two connection points
|
|
pEnum=new CEnumConnectionPoints(this, SMIR_NUMBER_OF_CONNECTION_POINTS, rgCP);
|
|
|
|
if (NULL==pEnum)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
pEnum->AddRef();
|
|
*ppEnum=pEnum;
|
|
return NOERROR;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnObject::FindConnectionPoint
|
|
*
|
|
* Purpose:
|
|
* Returns a pointer to the IConnectionPoint for a given
|
|
* outgoing IID.
|
|
*
|
|
* Parameters:
|
|
* riid REFIID of the outgoing interface for which
|
|
* a connection point is desired.
|
|
* ppCP IConnectionPoint ** in which to return
|
|
* the pointer after calling AddRef.
|
|
*
|
|
* Return Value:
|
|
* HRESULT NOERROR if the connection point is found,
|
|
* E_NOINTERFACE if it's not supported.
|
|
*/
|
|
|
|
STDMETHODIMP CSmirConnObject::FindConnectionPoint(REFIID riid
|
|
, IConnectionPoint **ppCP)
|
|
{
|
|
*ppCP=NULL;
|
|
HRESULT result;
|
|
if (IID_ISMIR_Notify==riid)
|
|
{
|
|
result = m_rgpConnPt[SMIR_NOTIFY_CONNECTION_POINT]
|
|
->QueryInterface(IID_IConnectionPoint, (PPVOID)ppCP);
|
|
if (NULL != ppCP)
|
|
return result;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
//Connection Point Enumerator follows
|
|
|
|
/*
|
|
* CEnumConnectionPoints::CEnumConnectionPoints
|
|
* CEnumConnectionPoints::~CEnumConnectionPoints
|
|
*
|
|
* Parameters (Constructor):
|
|
* pUnkRef LPUNKNOWN to use for reference counting.
|
|
* cPoints ULONG number of connection points in prgpCP
|
|
* rgpCP IConnectionPoint** to the array to enumerate.
|
|
*/
|
|
|
|
CEnumConnectionPoints::CEnumConnectionPoints(LPUNKNOWN pUnkRef
|
|
, ULONG cPoints, IConnectionPoint **rgpCP) : m_rgpCP ( NULL )
|
|
{
|
|
UINT i;
|
|
|
|
m_cRef=0;
|
|
m_pUnkRef=pUnkRef;
|
|
|
|
m_iCur=0;
|
|
m_cPoints=cPoints;
|
|
m_rgpCP=new IConnectionPoint *[(UINT)cPoints];
|
|
|
|
if (NULL!=m_rgpCP)
|
|
{
|
|
for (i=0; i < cPoints; i++)
|
|
{
|
|
m_rgpCP[i]=rgpCP[i];
|
|
m_rgpCP[i]->AddRef();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
CEnumConnectionPoints::~CEnumConnectionPoints(void)
|
|
{
|
|
if (NULL!=m_rgpCP)
|
|
{
|
|
UINT i;
|
|
|
|
for (i=0; i < m_cPoints; i++)
|
|
m_rgpCP[i]->Release();
|
|
|
|
delete [] m_rgpCP;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* CEnumConnectionPoints::QueryInterface
|
|
* CEnumConnectionPoints::AddRef
|
|
* CEnumConnectionPoints::Release
|
|
*
|
|
* Purpose:
|
|
* IUnknown members for CEnumConnectionPoints object.
|
|
*/
|
|
|
|
STDMETHODIMP CEnumConnectionPoints::QueryInterface(REFIID riid
|
|
, LPVOID *ppv)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
if (IID_IUnknown==riid || IID_IEnumConnectionPoints==riid)
|
|
*ppv=(LPVOID)this;
|
|
|
|
if (NULL!=*ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CEnumConnectionPoints::AddRef(void)
|
|
{
|
|
InterlockedIncrement(&m_cRef);
|
|
m_pUnkRef->AddRef();
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CEnumConnectionPoints::Release(void)
|
|
{
|
|
m_pUnkRef->Release();
|
|
|
|
long ret;
|
|
if (0L!=(ret=InterlockedDecrement(&m_cRef)))
|
|
return ret;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CEnumConnectionPoints::Next
|
|
*
|
|
* Purpose:
|
|
* Returns the next element in the enumeration.
|
|
*
|
|
* Parameters:
|
|
* cPoints ULONG number of connection points to return.
|
|
* ppCP IConnectionPoint** in which to store the returned
|
|
* pointers.
|
|
* pulEnum ULONG * in which to return how many we
|
|
* enumerated.
|
|
*
|
|
* Return Value:
|
|
* HRESULT NOERROR if successful, S_FALSE otherwise,
|
|
*/
|
|
|
|
STDMETHODIMP CEnumConnectionPoints::Next(ULONG cPoints
|
|
, IConnectionPoint **ppCP, ULONG *pulEnum)
|
|
{
|
|
ULONG cReturn=0L;
|
|
|
|
if (NULL==m_rgpCP)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
if (NULL==ppCP)
|
|
return ResultFromScode(E_POINTER);
|
|
|
|
if (NULL==pulEnum)
|
|
{
|
|
if (1L!=cPoints)
|
|
return ResultFromScode(E_POINTER);
|
|
}
|
|
else
|
|
*pulEnum=0L;
|
|
|
|
if (NULL==*ppCP || m_iCur >= m_cPoints)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
while (m_iCur < m_cPoints && cPoints > 0)
|
|
{
|
|
*ppCP=m_rgpCP[m_iCur++];
|
|
|
|
if (NULL!=*ppCP)
|
|
(*ppCP)->AddRef();
|
|
|
|
ppCP++;
|
|
cReturn++;
|
|
cPoints--;
|
|
}
|
|
|
|
if (NULL!=pulEnum)
|
|
*pulEnum=cReturn;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CEnumConnectionPoints::Skip(ULONG cSkip)
|
|
{
|
|
if (((m_iCur+cSkip) >= m_cPoints) || NULL==m_rgpCP)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
m_iCur+=cSkip;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CEnumConnectionPoints::Reset(void)
|
|
{
|
|
m_iCur=0;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CEnumConnectionPoints::Clone
|
|
(LPENUMCONNECTIONPOINTS *ppEnum)
|
|
{
|
|
PCEnumConnectionPoints pNew = NULL ;
|
|
|
|
*ppEnum=NULL;
|
|
|
|
//Create the clone
|
|
pNew=new CEnumConnectionPoints(m_pUnkRef, m_cPoints, m_rgpCP);
|
|
|
|
if (NULL==pNew)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
pNew->AddRef();
|
|
pNew->m_iCur=m_iCur;
|
|
|
|
*ppEnum=pNew;
|
|
return NOERROR;
|
|
}
|
|
/*
|
|
* CSmirEnumClassCP/CSmirNotifyCP::
|
|
*
|
|
* Purpose:
|
|
* Provides the notify connection point advise, unadvise constructor and destructor.
|
|
*
|
|
* Parameters:
|
|
* pUnkSink LPUNKNOWN to the sink to notify. The connection
|
|
* point must QueryInterface on this pointer to obtain
|
|
* the proper interface to call. The connection
|
|
* point must also insure that any pointer held has
|
|
* a reference count (QueryInterface will do it).
|
|
* pdwCookie DWORD * in which to store the connection key for
|
|
* later calls to Unadvise.
|
|
*/
|
|
|
|
CSmirNotifyCP :: CSmirNotifyCP(PCSmirConnObject pCO, REFIID riid, CSmir *pSmir):
|
|
CSmirConnectionPoint(pCO,riid,pSmir), m_evtConsumer (NULL)
|
|
{
|
|
// CSMIRClassFactory::objectsInProgress++;
|
|
m_bRegistered = FALSE;
|
|
m_evtConsumer = new CSmirWbemEventConsumer(pSmir);
|
|
void* tmp = NULL;
|
|
|
|
if (FAILED(m_evtConsumer->QueryInterface(IID_ISMIR_WbemEventConsumer, &tmp)))
|
|
{
|
|
delete m_evtConsumer;
|
|
m_evtConsumer = NULL;
|
|
}
|
|
}
|
|
|
|
CSmirNotifyCP :: ~CSmirNotifyCP()
|
|
{
|
|
if (NULL != m_evtConsumer)
|
|
{
|
|
m_evtConsumer->Release();
|
|
}
|
|
// CSMIRClassFactory::objectsInProgress--;
|
|
}
|
|
|
|
/*
|
|
* CSmirConnObject::TriggerEvent
|
|
*
|
|
* Purpose:
|
|
* Functions to make each connection point generate calls
|
|
* to any connected sinks. Since these functions are specific
|
|
* to IDuckEvents, they only deal with the connection point
|
|
* for that one interface
|
|
*
|
|
* Parameters:
|
|
* iEvent UINT of the event to trigger, either
|
|
* EVENT_QUACK, EVENT_FLAP, or EVENT_PADDLE.
|
|
*
|
|
* Return Value:
|
|
* BOOL TRUE events are triggered, FALSE if there
|
|
* are no connected sinks.
|
|
*/
|
|
|
|
BOOL CSmirNotifyCP::TriggerEvent()
|
|
{
|
|
IEnumConnections *pEnum = NULL ;
|
|
CONNECTDATA cd ;
|
|
|
|
if (FAILED(EnumConnections(&pEnum)))
|
|
return FALSE;
|
|
|
|
while (NOERROR == pEnum->Next(1, &cd, NULL))
|
|
{
|
|
//a promise fulfilled - Andrew Sinclair just in case anyone thinks otherwise!
|
|
ISMIRNotify *pJudith;
|
|
|
|
if (SUCCEEDED(cd.pUnk->QueryInterface(IID_ISMIR_Notify, (PPVOID)&pJudith)))
|
|
{
|
|
pJudith->ChangeNotify();
|
|
pJudith->Release();
|
|
}
|
|
|
|
cd.pUnk->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STDMETHODIMP CSmirNotifyCP::Advise(CSmir* pSmir, LPUNKNOWN pUnkSink
|
|
, DWORD *pdwCookie)
|
|
{
|
|
if (NULL == m_evtConsumer)
|
|
{
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
//if this is the first person to connect
|
|
if(m_Connections.IsEmpty())
|
|
{
|
|
//register for WBEM Events for Smir Namespace changes
|
|
if (SUCCEEDED(m_evtConsumer->Register(pSmir)))
|
|
{
|
|
m_bRegistered = TRUE;
|
|
}
|
|
}
|
|
|
|
return CSmirConnectionPoint::Advise(pUnkSink, pdwCookie);
|
|
}
|
|
|
|
STDMETHODIMP CSmirNotifyCP::Unadvise(CSmir* pSmir, DWORD dwCookie)
|
|
{
|
|
EnterCriticalSection ( & g_CriticalSection ) ;
|
|
|
|
HRESULT hr = CSmirConnectionPoint::Unadvise(dwCookie);
|
|
IWbemServices *t_pServ = NULL;
|
|
|
|
if(S_OK== hr)
|
|
{
|
|
//if this is the last connection unregister for WBEM Events
|
|
if(m_Connections.IsEmpty())
|
|
{
|
|
if (NULL == m_evtConsumer)
|
|
{
|
|
return WBEM_E_FAILED;
|
|
}
|
|
else if (m_bRegistered)
|
|
{
|
|
hr = m_evtConsumer->GetUnRegisterParams(&t_pServ);
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection ( & g_CriticalSection ) ;
|
|
|
|
if (SUCCEEDED(hr) && (t_pServ != NULL))
|
|
{
|
|
hr = m_evtConsumer->UnRegister(pSmir, t_pServ);
|
|
t_pServ->Release();
|
|
t_pServ = NULL;
|
|
|
|
//guarantees only one query at a time with the event consumer (sink)....
|
|
EnterCriticalSection ( & g_CriticalSection ) ;
|
|
m_bRegistered = FALSE;
|
|
LeaveCriticalSection ( & g_CriticalSection ) ;
|
|
}
|
|
|
|
return hr;
|
|
}
|