Leaked source code of windows server 2003
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.
 
 
 
 
 
 

872 lines
18 KiB

/*++
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 Error code or S_OK
*/
STDMETHODIMP
CImpIConnPtCont::EnumConnectionPoints (
OUT LPENUMCONNECTIONPOINTS *ppIEnum
)
{
CImpIEnumConnPt *pEnum;
HRESULT hr = S_OK;
if (ppIEnum == NULL) {
return E_POINTER;
}
pEnum = new CImpIEnumConnPt(this, apIIDConnectPt, CONNECTION_POINT_CNT);
if (pEnum == NULL) {
hr = E_OUTOFMEMORY;
}
else {
try {
*ppIEnum = NULL;
hr = pEnum->QueryInterface(IID_IEnumConnectionPoints, (PPVOID)ppIEnum);
} catch (...) {
hr = E_POINTER;
}
}
if (FAILED(hr) && pEnum) {
delete pEnum;
}
return hr;
}
/*
* 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
)
{
HRESULT hr = S_OK;
PCImpIConnectionPoint pConnPt = NULL;
if (ppCP == NULL) {
return E_POINTER;
}
//
// 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 {
hr = E_NOINTERFACE;
}
if (SUCCEEDED(hr)) {
try {
*ppCP=NULL;
//
// Return the IConnectionPoint interface
//
hr = pConnPt->QueryInterface(IID_IConnectionPoint, (PPVOID)ppCP);
} catch (...) {
hr = E_POINTER;
}
}
return hr;
}
/*
* 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
)
{
HRESULT hr = S_OK;
if (ppv == NULL) {
return E_POINTER;
}
try {
*ppv = NULL;
if (IID_IUnknown==riid || IID_IConnectionPoint==riid) {
*ppv = (PVOID)this;
AddRef();
}
else {
hr = E_NOINTERFACE;
}
} catch (...) {
hr = E_POINTER;
}
return hr;
}
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
*/
BOOL
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();
if (dwStat != ERROR_SUCCESS) {
return FALSE;
}
return TRUE;
}
/*
* 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
)
{
HRESULT hr = S_OK;
if (pIID == NULL) {
return E_POINTER;
}
try {
*pIID = *apIIDConnectPt[m_iConnPtType];
} catch (...) {
hr = E_POINTER;
}
return hr;
}
/*
* 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
)
{
HRESULT hr = S_OK;
if (ppCPC == NULL) {
return E_POINTER;
}
try {
*ppCPC = NULL;
m_pObj->QueryInterface(IID_IConnectionPointContainer, (void **)ppCPC);
} catch (...) {
hr = E_POINTER;
}
return hr;
}
/*
* 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 = S_OK;
if (pUnkSink == NULL || pdwCookie == NULL) {
return E_POINTER;
}
//
// Can only support one connection
//
if (NULL != m_Connection.pIDirect) {
hr = CONNECT_E_ADVISELIMIT;
}
else {
try {
*pdwCookie = 0;
//
// Get interface from sink
//
hr = pUnkSink->QueryInterface(*apIIDConnectPt[m_iConnPtType], (PPVOID)&m_Connection);
if (SUCCEEDED(hr)) {
//
// Return our cookie
//
*pdwCookie = eAdviseKey;
}
} catch (...) {
hr = E_POINTER;
}
}
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 CONNECT_E_NOCONNECTION;
EnterUnadvise();
m_Connection.pIDirect = NULL;
ExitUnadvise();
return S_OK;
}
/*
* CImpIConnectionPoint::EnumConnections
*
* Purpose:
* Not implemented because only one conection is allowed
*/
STDMETHODIMP
CImpIConnectionPoint::EnumConnections (
OUT LPENUMCONNECTIONS *ppEnum
)
{
HRESULT hr = E_NOTIMPL;
if (ppEnum == NULL) {
return E_POINTER;
}
try {
*ppEnum = NULL;
} catch (...) {
hr = E_POINTER;
}
return hr;
}
/*
* 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
)
{
HRESULT hr = S_OK;
if (ppv == NULL) {
return E_POINTER;
}
try {
*ppv = NULL;
if ((riid == IID_IUnknown) || (riid == IID_IEnumConnectionPoints)) {
*ppv = this;
AddRef();
} else {
hr = E_NOINTERFACE;
}
} catch (...) {
hr = E_POINTER;
}
return hr;
}
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 = S_OK;
if (apConnPt == NULL) {
return E_POINTER;
}
try {
//
// 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 (pcReturned) {
*pcReturned = cRet;
}
} catch (...) {
hr = E_POINTER;
}
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 S_FALSE;
}
return 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 = NULL;
HRESULT hr = S_OK;
if (ppEnum == NULL) {
return E_POINTER;
}
try {
*ppEnum = NULL;
// Create new enumerator
pNewEnum = new CImpIEnumConnPt(m_pConnPtCont, m_apIID, m_cItems);
if (pNewEnum != NULL) {
// Copy current position
pNewEnum->m_uCurrent = m_uCurrent;
*ppEnum = pNewEnum;
}
else {
hr = E_OUTOFMEMORY;
}
} catch (...) {
hr = E_POINTER;
}
if (FAILED(hr) && pNewEnum) {
delete pNewEnum;
}
return hr;
}