www.pudn.com > GEOPC_modified_2005621145656299.rar > ImpIConnectionPoint.cpp, change:2005-04-08,size:12419b


// ImpIConnectionPoint.cpp 
// 
//  This file contains the implementation of the IConnectionPoint interface 
//  tear-off interface for the OPC Data Access and Alarms & Events servers 
// 
//  NOTE that this ConnectionPoint is NOT tear off interfaces from the server, 
//  It is a 'real' object separate from the server. 
// 
//	(c) COPYRIGHT 1999, INTELLUTION INC. 
//	ALL RIGHTS RESERVED 
// 
// 
//	Functions defined in this module: 
// 
//			CImpIConnectionPoint::CImpIConnectionPoint() 
//			CImpIConnectionPoint::~CImpIConnectionPoint() 
//			CImpIConnectionPoint::QueryInterface() 
//			CImpIConnectionPoint::GetConnectionInterface() 
//			CImpIConnectionPoint::GetConnectionPointContainer() 
//			CImpIConnectionPoint::Advise() 
//			CImpIConnectionPoint::Unadvise() 
//			CImpIConnectionPoint::EnumConnections() 
//			CImpIConnectionPoint::CleanupSinks() 
// 
// 
// Modification Log: 
//	Vers	Date		By		Notes 
//	----	--------	---		----- 
//	7.20	04/26/99	jra		Created for Data Access 2.0 and Alarms & Events 1.0 support 
//	7.20a	01/24/2001	mvs		Modified CImpIConnectionPoint::AddRef() and Release() - 
//								Do not pass along to the outer object,  
//								else we will end up in a circular object count loop. 
//								Just increment the refrence count. 
// 
// 
// 
#define WIN32_LEAN_AND_MEAN 
 
#include "implconnect.h" 
 
 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | CImpIConnectionPoint() | Constructor 
// 
// @parm	IN IUnknown *	| pUnk	| Parent container object 
// @parm	IN IID			| iid	| Interface associated with this CP 
// @parm	IN OPTIONAL HRESULT (*)(IUnknown *, BOOL) | lpfn	| Optional callback function 
//		used to notify the parent of an Advise() or Unadvise() 
// 
// @rvalue	none 
// 
CImpIConnectionPoint::CImpIConnectionPoint(IUnknown			*	pUnk, 
										   IID					iid, 
										   IN OPTIONAL HRESULT (*lpfn)(IUnknown *, BOOL)) :	/* = NULL */ 
	m_pUnkOuter(pUnk), m_iid(iid), m_lpfnAdviseNotify(lpfn) 
{ 
//	OPC_TRACE("Connection Point object created (0x%08X)", this); 
 
	// Initialize the data members 
	m_lRefCount     = 0L; 
	m_pCallBack		= NULL; 
 
	// Enable OnDataChange() initially 
	m_bEnabled		= TRUE; 
 
	InitializeCriticalSection(&m_Lock); 
} 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | ~CImpIConnectionPoint() | Destructor 
// 
// @parm	none 
// 
// @rvalue	none 
// 
CImpIConnectionPoint::~CImpIConnectionPoint(void) 
{ 
	// Release any client callbacks 
	CleanupSinks(); 
 
	DeleteCriticalSection(&m_Lock); 
 
//	OPC_TRACE("Connection Point object deleted (0x%08X)", this); 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// 
// IUnknown interface implementation 
// 
///////////////////////////////////////////////////////////////////////////// 
 
 
 
//---(MEMBER FUNCTION)---------------------------------------------------- 
// 
// @mfunc	ULONG | CImpIConnectionPoint | QueryInterface | Standard IUnknown QueryInterface() 
// 
// @parm	IN REFIID	 | riid | Interface requested 
// @parm	OUT LPVOID * | ppv	| Returned interface pointer 
// 
// @rvalue	S_OK			| Success 
// @rvalue	E_INVALIDARG	| An invalid argument was passed 
// @rvalue	E_OUTOFMEMORY	| A memory allocated failed 
// @rvalue	E_NOINTERFACE	| The object does not support the requested interface 
// 
STDMETHODIMP CImpIConnectionPoint::QueryInterface(REFIID	riid,  
												  LPVOID	*ppv) 
{ 
	char	szIntf[100]; 
 
 
	// Make sure we got a valid pointer 
	if (NULL == ppv) 
	{ 
		return E_INVALIDARG; 
	} 
 
	// Init to NULL 
	*ppv = NULL; 
 
	if (IID_IUnknown == riid) 
	{ 
		*ppv = static_cast<IUnknown *>(this); 
 
		strcpy(szIntf, "IUnknown"); 
	} 
	else if (IID_IConnectionPoint == riid) 
	{ 
		*ppv = static_cast<IConnectionPoint *>(this); 
 
		strcpy(szIntf, "IConnectionPoint"); 
	} 
	else 
	{ 
		// No interface available 
		return E_NOINTERFACE; 
	} 
 
//	OPC_TRACE("CImpIConnectionPoint::QueryInterface() for %s for object 0x%08X", szIntf, this); 
 
	// AddRef the server for each tear off interface created. 
	(reinterpret_cast<IUnknown *>(*ppv))->AddRef(); 
	return S_OK; 
} 
 
 
//---(MEMBER FUNCTION)---------------------------------------------------- 
// 
// @mfunc	ULONG | CImpIConnectionPoint | AddRef | Standard IUnknown AddRef() 
// 
// @parm	none 
// 
// @rvalue	Current reference count 
// 
STDMETHODIMP_(ULONG) CImpIConnectionPoint::AddRef(void) 
{ 
	//	mvs01242001 - Implemented in object 
	//	Do not pass this along to the outer object, else we will end up in  
	//	a circular object count loop. Just increment the refrence count. 
	return InterlockedIncrement(&m_lRefCount); 
} 
 
 
//---(MEMBER FUNCTION)---------------------------------------------------- 
// 
// @mfunc	ULONG | CImpIConnectionPoint | Release | Standard IUnknown Release() 
// 
// @parm	none 
// 
// @rvalue	Current reference count 
// 
STDMETHODIMP_(ULONG) CImpIConnectionPoint::Release(void) 
{ 
	//	mvs01242001 -  Implemented in object 
	//	Do not pass this along to the outer object, else we will end up in  
	//	a circular object count loop. Just decrement the refrence count. 
	ULONG currentCount = InterlockedDecrement(&m_lRefCount); 
	if (0 == currentCount) 
	{ 
		delete this; 
	} 
	return currentCount; 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// 
// IConnectionPoint interface implementation 
// 
///////////////////////////////////////////////////////////////////////////// 
 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | GetConnectionInterface() | Returns the IID for 
//		the current connection point interface 
// 
// @parm	OUT IID * | pIID | Returned guid (IID) 
// 
// @rvalue	S_OK		| Success 
// @rvalue	E_POINTER	| An invalid pointer was passed 
// @rvalue	E_FAIL		| General failure 
// 
STDMETHODIMP CImpIConnectionPoint::GetConnectionInterface(IID	*	pIID) 
{ 
	// Check for NULL pointers 
	if (NULL == pIID) 
	{ 
		return E_POINTER; 
	} 
 
	// Init return arguments 
	*pIID = m_iid; 
	return S_OK; 
} 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | GetConnectionPointContainer() | Returns a pointer 
//		to the container for this connection point 
// 
// @parm	OUT IConnectionPointContainer ** | ppCPC | Returned container interface) 
// 
// @rvalue	S_OK	| Success 
// 
STDMETHODIMP CImpIConnectionPoint::GetConnectionPointContainer(OUT IConnectionPointContainer **ppCPC) 
{ 
	return m_pUnkOuter->QueryInterface(IID_IConnectionPointContainer, (void **)ppCPC); 
} 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | Advise() | Allows a client to "connect" 
//		its sink to the connection point 
// 
// @parm	IN IUnknown * | pUnkSink	| Client's sink (must call QI, not use directly!!!) 
// @parm	OUT DWORD *	  | pdwCookie	| Returned connection cookie (used for Dadvise()) 
// 
// @rvalue	S_OK					| Success 
// @rvalue	CONNECT_E_ADVISELIMIT	| A connection already exists and the limit is reached 
// @rvalue	CONNECT_E_CANNOTCONNECT	| Unable to establish the connection (QI failed) 
// @rvalue	E_POINTER				| An invalid pointer was received 
// @rvalue	E_FAIL					| General failure 
// 
STDMETHODIMP CImpIConnectionPoint::Advise(IN IUnknown	*	pUnkSink, 
										  OUT DWORD		*	pdwCookie) 
{ 
	// Validate pointers and init return arguments 
	BEGIN_INOUT_PARAMS() 
		IN_PARAM(pUnkSink) 
		OUT_PARAM(pdwCookie) 
	END_INOUT_PARAMS(E_POINTER) 
 
 
	// If already in use, return error 
	if (m_pCallBack) 
	{ 
		return CONNECT_E_ADVISELIMIT; 
	} 
 
	// Inform the parent object of the Advise() if necessary and let it 
	// perform any startup logic 
	if (m_lpfnAdviseNotify) 
	{ 
		if (FAILED(m_lpfnAdviseNotify(m_pUnkOuter, TRUE))) 
		{ 
			return CONNECT_E_CANNOTCONNECT; 
		} 
	} 
 
	// Make sure the passed interface supports the right callback 
	HRESULT hr = S_OK; 
	if (FAILED(hr = pUnkSink->QueryInterface(m_iid, (LPVOID *)&m_pCallBack))) 
	{ 
		m_pCallBack = NULL; 
		return CONNECT_E_CANNOTCONNECT; 
	} 
//	ASSERT(m_pCallBack); 
 
//	OPC_TRACE("IConnectionPoint::Advise() connected (0x%08X)", this); 
 
	// Since only one connection is supported, the cookie is always the "this" pointer 
	*pdwCookie = reinterpret_cast<DWORD>(this); 
	return S_OK; 
} 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | Unadvise() | Allows a client to "disconnect" 
//		its sink from the connection point 
// 
// @parm	IN DWORD | dwCookie | Connection cookie returned from Advise() 
// 
// @rvalue	S_OK					| Success 
// @rvalue	CONNECT_E_NOCONNECTION	| The passed cookie is invalid or no connection exists 
// 
STDMETHODIMP CImpIConnectionPoint::Unadvise(IN DWORD dwCookie) 
{ 
	// Since only one connection is supported, the cookie is always the "this" pointer 
	if (reinterpret_cast<DWORD>(this) != dwCookie) 
	{ 
		return CONNECT_E_NOCONNECTION; 
	} 
 
	// If no current subscriptions, then nothing to unadvise 
	if (NULL == m_pCallBack) 
	{ 
		return CONNECT_E_NOCONNECTION; 
	} 
 
	// Release the client's callback 
	CleanupSinks(); 
 
	// Inform the parent object of the Unadvise() if necessary 
	if (m_lpfnAdviseNotify) 
	{ 
		m_lpfnAdviseNotify(m_pUnkOuter, FALSE); 
	} 
 
//	OPC_TRACE("IConnectionPoint::Unadvise() disconnected (0x%08X)", this); 
	return S_OK; 
} 
         
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | EnumConnections() | Returns an enumerator 
//		of all current connections to the connection point 
// 
// @parm	OUT IEnumConnections ** | ppEnum | Returned connections 
// 
// @rvalue	S_OK			| Success 
// @rvalue	E_POINTER		| An invalid pointer was passed 
// @rvalue	E_OUTOFMEMORY	| a memory allocator failed 
// 
STDMETHODIMP CImpIConnectionPoint::EnumConnections(OUT IEnumConnections	**	ppEnum) 
{ 
	CImpIEnumConnections	*pEnum	= NULL; 
 
	CONNECTDATA				ConnectData; 
	CONNECTDATA				*pData	= NULL; 
 
	ULONG					lCount	= 0L; 
 
	HRESULT					hr; 
 
 
	// Validate pointers and init return arguments 
	BEGIN_INOUT_PARAMS() 
		OUT_PARAM(ppEnum) 
	END_INOUT_PARAMS(E_POINTER) 
 
 
	// If the connection point is active, setup the info. 
	// Else we will create an empty enumerator. 
	if (m_pCallBack) 
	{ 
		// Setup the CONNECTDATA struct for the enumerator 
		pData = &ConnectData; 
		 
		pData->pUnk = m_pCallBack; 
		pData->dwCookie = reinterpret_cast<DWORD>(this); 
 
		// Get the number of active connections (currently 1) 
		lCount = sizeof(ConnectData) / sizeof(CONNECTDATA); 
	} 
 
	// Create the new eumerator 
	if (NULL == (pEnum = new CImpIEnumConnections(this, lCount, pData))) 
	{ 
		return E_OUTOFMEMORY; 
	} 
 
	// Record our temp reference to the object 
	pEnum->AddRef(); 
 
	// Get an interface for the caller 
	hr = pEnum->QueryInterface(IID_IEnumConnections, (void **)ppEnum); 
 
	// Release our temp reference to the object. If the above QI failed, this will delete it 
	SAFE_RELEASE(pEnum); 
 
	return hr; 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// 
// Private (non-OPC) Utility Functions 
// 
///////////////////////////////////////////////////////////////////////////// 
 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | SetEnabled() | Enables or disabled OnDataChange() 
//		callbacks for the connection point 
// 
// @parm	IN BOOL	| bEnabled | New enabled state 
// 
// @rvalue	none 
// 
void CImpIConnectionPoint::SetEnabled(IN BOOL bEnabled) 
{ 
	if (bEnabled != m_bEnabled) 
	{ 
		// Save the new state 
		m_bEnabled = bEnabled; 
	} 
} 
 
 
//----(Member Function)------------------------------------------------------- 
// 
// @mfunc void | CImpIConnectionPoint | CleanupSinks() | Releases any callback interfaces 
// 
// @parm	none 
// 
// @rvalue	none 
// 
void CImpIConnectionPoint::CleanupSinks(void) 
{ 
	// Lock the object in case it is currently being processed 
	Lock(); 
 
	try 
	{ 
		if (m_pCallBack) 
		{ 
			SAFE_RELEASE(m_pCallBack); 
		} 
	} 
	catch(...) 
	{ 
//		ASSERT(FALSE); 
	} 
 
	// Unlock the object 
	UnLock(); 
}