windows-nt/Source/XPSP1/NT/admin/controls/smonctrl/iconnpt.cpp
2020-09-26 16:20:57 +08:00

742 lines
15 KiB
C++

/*++
Copyright (C) 1993-1999 Microsoft Corporation
Module Name:
iconnpt.cpp
Abstract:
Implementation of CImpIConnectionPoint for the Polyline object
as well as CConnectionPoint.
--*/
#include "polyline.h"
#include "iconnpt.h"
#include "unkhlpr.h"
static const IID *apIIDConnectPt [CONNECTION_POINT_CNT] = {
&IID_ISystemMonitorEvents,
&DIID_DISystemMonitorEvents
};
// CImpIConnPt interface implementation
IMPLEMENT_CONTAINED_IUNKNOWN(CImpIConnPtCont)
/*
* CImpIConnPtCont::CImpIConnPtCont
*
* Purpose:
* Constructor.
*
* Return Value:
*/
CImpIConnPtCont::CImpIConnPtCont ( PCPolyline pObj, LPUNKNOWN pUnkOuter)
: m_cRef(0),
m_pObj(pObj),
m_pUnkOuter(pUnkOuter)
{
return;
}
/*
* CImpIConnPtCont::~CImpIConnPtCont
*
* Purpose:
* Destructor.
*
* Return Value:
*/
CImpIConnPtCont::~CImpIConnPtCont( void )
{
return;
}
/*
* CImpIConnPtCont::EnumConnectionPoints
*
* Purpose:
* Not implemented.
*
* Return Value:
* HRESULT E_NOTIMPL
*/
STDMETHODIMP
CImpIConnPtCont::EnumConnectionPoints (
OUT LPENUMCONNECTIONPOINTS *ppIEnum
)
{
CImpIEnumConnPt *pEnum;
if (ppIEnum == NULL)
return E_POINTER;
*ppIEnum = NULL;
pEnum = new CImpIEnumConnPt(this, apIIDConnectPt, CONNECTION_POINT_CNT);
if (pEnum == NULL)
return E_OUTOFMEMORY;
return pEnum->QueryInterface(IID_IEnumConnectionPoints, (PPVOID)ppIEnum);
}
/*
* CImpIConnPtCont::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
CImpIConnPtCont::FindConnectionPoint (
IN REFIID riid,
OUT IConnectionPoint **ppCP
)
{
PCImpIConnectionPoint pConnPt;
*ppCP=NULL;
// if request matches one of our connection IDs
if (IID_ISystemMonitorEvents == riid)
pConnPt = &m_pObj->m_ConnectionPoint[eConnectionPointDirect];
else if (DIID_DISystemMonitorEvents == riid)
pConnPt = &m_pObj->m_ConnectionPoint[eConnectionPointDispatch];
else
return ResultFromScode(E_NOINTERFACE);
// Return the IConnectionPoint interface
return pConnPt->QueryInterface(IID_IConnectionPoint, (PPVOID)ppCP);
}
/*
* CImpIConnectionPoint constructor
*/
CImpIConnectionPoint::CImpIConnectionPoint (
void
)
: m_cRef(0),
m_pObj(NULL),
m_pUnkOuter(NULL),
m_hEventEventSink(NULL),
m_lSendEventRefCount(0),
m_lUnadviseRefCount(0)
{
m_Connection.pIDirect = NULL;
m_Connection.pIDispatch = NULL;
}
/*
* CImpIConnectionPoint destructor
*/
CImpIConnectionPoint::~CImpIConnectionPoint (
void
)
{
DeinitEventSinkLock();
}
/*
* CImpIConnectionPoint::QueryInterface
* CImpIConnectionPoint::AddRef
* CCImpIonnectionPoint::Release
*
*/
STDMETHODIMP
CImpIConnectionPoint::QueryInterface (
IN REFIID riid,
OUT LPVOID *ppv
)
{
*ppv=NULL;
if (IID_IUnknown==riid || IID_IConnectionPoint==riid)
*ppv=(LPVOID)this;
if (NULL != *ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG)
CImpIConnectionPoint::AddRef(
void
)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}
STDMETHODIMP_(ULONG)
CImpIConnectionPoint::Release (
void
)
{
--m_cRef;
return m_pUnkOuter->Release();
}
/*
* CImpIConnectionPoint::Init
*
* Purpose:
* Set back-pointers and connection type.
*
* Paramters:
* pObj Containing Object
* pUnkOuter Controlling Object
* iConnectType Connection point type
*/
void
CImpIConnectionPoint::Init (
IN PCPolyline pObj,
IN LPUNKNOWN pUnkOuter,
IN INT iConnPtType
)
{
DWORD dwStat = 0;
m_pObj = pObj;
m_pUnkOuter = pUnkOuter;
m_iConnPtType = iConnPtType;
dwStat = InitEventSinkLock();
}
/*
* CImpIConnectionPoint::GetConnectionInterface
*
* Purpose:
* Returns the IID of the outgoing interface supported through
* this connection point.
*
* Parameters:
* pIID IID * in which to store the IID.
*/
STDMETHODIMP
CImpIConnectionPoint::GetConnectionInterface (
OUT IID *pIID
)
{
if (NULL == pIID)
return ResultFromScode(E_POINTER);
*pIID = *apIIDConnectPt[m_iConnPtType];
return NOERROR;
}
/*
* CImpIConnectionPoint::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
CImpIConnectionPoint::GetConnectionPointContainer (
OUT IConnectionPointContainer **ppCPC
)
{
return m_pObj->QueryInterface(IID_IConnectionPointContainer, (void **)ppCPC);
}
/*
* CImpIConnectionPoint::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
CImpIConnectionPoint::Advise (
IN LPUNKNOWN pUnkSink,
OUT DWORD *pdwCookie )
{
HRESULT hr;
*pdwCookie = 0;
// Can only support one connection
if (NULL != m_Connection.pIDirect) {
hr = ResultFromScode(CONNECT_E_ADVISELIMIT);
} else {
// Get interface from sink
if (FAILED(pUnkSink->QueryInterface(*apIIDConnectPt[m_iConnPtType], (PPVOID)&m_Connection)))
hr = ResultFromScode(CONNECT_E_CANNOTCONNECT);
else {
// Return our cookie
*pdwCookie = eAdviseKey;
hr = NOERROR;
}
}
return hr;
}
/*
* CImpIConnectionPoint::SendEvent
*
* Purpose:
* Sends an event to the attached event sink
*
* Parameters:
* uEventType Event code
* dwParam Parameter to send with event
*
*/
void
CImpIConnectionPoint::SendEvent (
IN UINT uEventType,
IN DWORD dwParam
)
{
// If not connected, just return.
if ( EnterSendEvent() ) {
if (m_Connection.pIDirect != NULL) {
// For direct connection, call the method
if (m_iConnPtType == eConnectionPointDirect) {
switch (uEventType) {
case eEventOnCounterSelected:
m_Connection.pIDirect->OnCounterSelected((INT)dwParam);
break;
case eEventOnCounterAdded:
m_Connection.pIDirect->OnCounterAdded((INT)dwParam);
break;
case eEventOnCounterDeleted:
m_Connection.pIDirect->OnCounterDeleted((INT)dwParam);
break;
case eEventOnSampleCollected:
m_Connection.pIDirect->OnSampleCollected();
break;
case eEventOnDblClick:
m_Connection.pIDirect->OnDblClick((INT)dwParam);
break;
}
}
// for dispatch connection, call Invoke
else if ( m_iConnPtType == eConnectionPointDispatch ) {
if ( NULL != m_Connection.pIDispatch ) {
DISPPARAMS dp;
VARIANT vaRet;
VARIANTARG varg;
VariantInit(&vaRet);
if ( uEventType == eEventOnSampleCollected ) {
SETNOPARAMS(dp)
} else {
VariantInit(&varg);
V_VT(&varg) = VT_I4;
V_I4(&varg) = (INT)dwParam;
SETDISPPARAMS(dp, 1, &varg, 0, NULL)
}
m_Connection.pIDispatch->Invoke(uEventType, IID_NULL
, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp
, &vaRet, NULL, NULL);
}
}
}
}
ExitSendEvent();
return;
}
/*
* CImpIConnectionPoint::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
CImpIConnectionPoint::Unadvise (
IN DWORD dwCookie )
{
if (eAdviseKey != dwCookie)
return ResultFromScode(CONNECT_E_NOCONNECTION);
EnterUnadvise();
m_Connection.pIDirect = NULL;
ExitUnadvise();
return NOERROR;
}
/*
* CImpIConnectionPoint::EnumConnections
*
* Purpose:
* Not implemented because only one conection is allowed
*/
STDMETHODIMP
CImpIConnectionPoint::EnumConnections (
OUT LPENUMCONNECTIONS *ppEnum
)
{
if (ppEnum == NULL)
return E_POINTER;
*ppEnum = NULL;
return ResultFromScode(E_NOTIMPL);
}
/*
* Locks for the event sink.
*/
DWORD
CImpIConnectionPoint::InitEventSinkLock ( void )
{
DWORD dwStat = 0;
m_lUnadviseRefCount = 0;
m_lSendEventRefCount = 0;
if ( NULL == ( m_hEventEventSink = CreateEvent ( NULL, TRUE, TRUE, NULL ) ) )
dwStat = GetLastError();
return dwStat;
}
void
CImpIConnectionPoint::DeinitEventSinkLock ( void )
{
// Release the event sink lock
if ( NULL != m_hEventEventSink ) {
CloseHandle ( m_hEventEventSink );
m_hEventEventSink = NULL;
}
m_lSendEventRefCount = 0;
m_lUnadviseRefCount = 0;
}
BOOL
CImpIConnectionPoint::EnterSendEvent ( void )
{
// Return value indicates whether lock is granted.
// If lock is not granted, must still call ExitSendEvent.
// Increment the SendEvent reference count when SendEvent is active.
InterlockedIncrement( &m_lSendEventRefCount );
// Grant the lock unless the event sink pointer is being modified in Unadvise.
return ( 0 == m_lUnadviseRefCount );
}
void
CImpIConnectionPoint::ExitSendEvent ( void )
{
LONG lTemp;
// Decrement the SendEvent reference count.
lTemp = InterlockedDecrement( &m_lSendEventRefCount );
// Signal the event sink if SendEvent count decremented to 0.
// lTemp is the value previous to decrement.
if ( 0 == lTemp )
SetEvent( m_hEventEventSink );
}
void
CImpIConnectionPoint::EnterUnadvise ( void )
{
BOOL bStatus;
bStatus = ResetEvent( m_hEventEventSink );
// Increment the Unadvise reference count whenever Unadvise is active.
// Whenever this is > 0, events are not fired.
InterlockedIncrement( &m_lUnadviseRefCount );
// Wait until SendEvent is no longer active.
while ( m_lSendEventRefCount > 0 ) {
WaitForSingleObject( m_hEventEventSink, eEventSinkWaitInterval );
bStatus = ResetEvent( m_hEventEventSink );
}
}
void
CImpIConnectionPoint::ExitUnadvise ( void )
{
// Decrement the Unadvise reference count.
InterlockedDecrement( &m_lUnadviseRefCount );
}
CImpIEnumConnPt::CImpIEnumConnPt (
IN CImpIConnPtCont *pConnPtCont,
IN const IID **ppIID,
IN ULONG cItems
)
{
m_pConnPtCont = pConnPtCont;
m_apIID = ppIID;
m_cItems = cItems;
m_uCurrent = 0;
m_cRef = 0;
}
STDMETHODIMP
CImpIEnumConnPt::QueryInterface (
IN REFIID riid,
OUT PVOID *ppv
)
{
if ((riid == IID_IUnknown) || (riid == IID_IEnumConnectionPoints)) {
*ppv = this;
AddRef();
return NOERROR;
}
*ppv = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG)
CImpIEnumConnPt::AddRef (
VOID
)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG)
CImpIEnumConnPt::Release(
VOID
)
{
if (--m_cRef == 0) {
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP
CImpIEnumConnPt::Next(
IN ULONG cItems,
OUT IConnectionPoint **apConnPt,
OUT ULONG *pcReturned)
{
ULONG i;
ULONG cRet;
HRESULT hr;
hr = NOERROR;
// Clear the return values
for (i = 0; i < cItems; i++)
apConnPt[i] = NULL;
// Try to fill the caller's array
for (cRet = 0; cRet < cItems; cRet++) {
// No more, return success with false
if (m_uCurrent == m_cItems) {
hr = S_FALSE;
break;
}
// Ask connection point container for next connection point
hr = m_pConnPtCont->FindConnectionPoint(*m_apIID[m_uCurrent], &apConnPt[cRet]);
if (FAILED(hr))
break;
m_uCurrent++;
}
// If failed, free the accumulated interfaces
if (FAILED(hr)) {
for (i = 0; i < cRet; i++)
ReleaseInterface(apConnPt[i]);
cRet = 0;
}
// If desired, return number of items fetched
if (pcReturned != NULL)
*pcReturned = cRet;
return hr;
}
/***
*HRESULT CImpIEnumConnPt::Skip(unsigned long)
*Purpose:
* Attempt to skip over the next 'celt' elements in the enumeration
* sequence.
*
*Entry:
* celt = the count of elements to skip
*
*Exit:
* return value = HRESULT
* S_OK
* S_FALSE - the end of the sequence was reached
*
***********************************************************************/
STDMETHODIMP
CImpIEnumConnPt::Skip(
IN ULONG cItems
)
{
m_uCurrent += cItems;
if (m_uCurrent > m_cItems)
m_uCurrent = m_cItems;
return (m_uCurrent == m_cItems) ? S_FALSE : S_OK;
}
/***
*HRESULT CImpIEnumConnPt::Reset(void)
*Purpose:
* Reset the enumeration sequence back to the beginning.
*
*Entry:
* None
*
*Exit:
* return value = SHRESULT CODE
* S_OK
*
***********************************************************************/
STDMETHODIMP
CImpIEnumConnPt::Reset(
VOID
)
{
m_uCurrent = 0;
return S_OK;
}
/***
*HRESULT CImpIEnumConnPt::Clone(IEnumVARIANT**)
*Purpose:
* Retrun a CPoint enumerator with exactly the same state as the
* current one.
*
*Entry:
* None
*
*Exit:
* return value = HRESULT
* S_OK
* E_OUTOFMEMORY
*
***********************************************************************/
STDMETHODIMP
CImpIEnumConnPt::Clone (
OUT IEnumConnectionPoints **ppEnum
)
{
CImpIEnumConnPt *pNewEnum;
*ppEnum = NULL;
// Create new enumerator
pNewEnum = new CImpIEnumConnPt(m_pConnPtCont, m_apIID, m_cItems);
if (pNewEnum == NULL)
return E_OUTOFMEMORY;
// Copy current position
pNewEnum->m_uCurrent = m_uCurrent;
*ppEnum = pNewEnum;
return NOERROR;
}