// EventSink.cpp: implementation of the CEventSink class.
//
// Author : David Shepherd
// Copyright (c) 2002, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "EventSink.h"
#include "EventSinkPassThrough.h"
/////////////////////////////////////////////////////////////////////////////
// CEventSink
CEventSink::CEventSink()
{
// initialise everything
m_SourceEventInterfaceGuid=GUID_NULL;
m_Cookie=0;
m_pNotifySink=NULL;
}
CEventSink::~CEventSink()
{
// clean up
if(m_Cookie!=0)
{
// disconnect from the event source
try { Disconnect(); }
catch(...)
{} // todo : recover from this
}
}
CComPtr<ITypeInfo> CEventSink::GetEventInterfaceTypeInfo()
{
// get the event source coclass type info
CComPtr<ITypeInfo> spTypeInfo=
GetImplementingCoClassTypeInfo(m_spSourceDispatch);
// return the event interface type info
return GetDefaultSourceInterfaceTypeInfo(spTypeInfo);
}
GUID CEventSink::GetEventInterfaceGuid()
{
// return the event interface guid
return CAutoTypeAttrPtr(GetEventInterfaceTypeInfo())->guid;
}
void CEventSink::ProcessEvent(DISPID DispatchId,
const DISPPARAMS *pDispParams,VARIANT *pResult)
{
// get the event interface type info
CComPtr<ITypeInfo> spTypeInfo=GetEventInterfaceTypeInfo();
// get the event name
CComBSTR EventName;
UINT Count=0;
if(!SUCCEEDED(spTypeInfo->GetNames(DispatchId,&EventName,1,&Count)))
{
throw std::exception();
}
ATLASSERT(Count==1);
// pack the parameters into a safe array
if(pDispParams->cNamedArgs!=0)
{
throw std::exception();
// todo : the correct error is DISP_E_NONAMEDARGS
}
// create the safe array
SAFEARRAY *pParams=NULL;
SAFEARRAYBOUND aDim[1];
aDim[0].lLbound=0;
aDim[0].cElements=pDispParams->cArgs;
pParams=SafeArrayCreate(VT_VARIANT,1,aDim);
if(pParams==NULL)
{
throw std::exception();
}
CAutoSafeArrayPtr AutoSafeArrayPtr(pParams);
// set the parameters
for(long l=0; l<(long)pDispParams->cArgs; l++)
{
if(!SUCCEEDED(SafeArrayPutElement(pParams,&l,
// reverse order
&pDispParams->rgvarg[pDispParams->cArgs-l-1])))
{
throw std::exception();
}
}
try // catch all errors from the sink
{
// process the event
m_pNotifySink->ESNS_ProcessEvent(
m_SourceName,BSTR2W(EventName),pParams,pResult);
}
catch(...)
{}
}
void CEventSink::Connect(
const std::wstring &Name,const CComPtr<IDispatch> &spDispatch,
CEventSinkNotifySink *pNotifySink)
{
// check parameters
ATLASSERT(spDispatch!=NULL);
ATLASSERT(pNotifySink!=NULL);
// save settings
m_SourceName=Name;
m_spSourceDispatch=spDispatch;
m_pNotifySink=pNotifySink;
// check the event interface is a dispatch interface
if(CAutoTypeAttrPtr(GetEventInterfaceTypeInfo())->typekind!=TKIND_DISPATCH)
{
throw std::exception();
}
// get the event interface guid
// this needs to be saved since type information may not later be available if
// the server dies before we have chance to disconnect from the event source
m_SourceEventInterfaceGuid=GetEventInterfaceGuid();
// create the event sink pass through
CComObject<CEventSinkPassThrough> *pPassThrough=NULL;
if(!SUCCEEDED(
CComObject<CEventSinkPassThrough>::CreateInstance(&pPassThrough)))
{
throw std::exception();
}
CComPtr<IUnknown> spUnknown(pPassThrough->GetUnknown());
pPassThrough->m_pEventSink=this;
pPassThrough->m_EventInterfaceGuid=m_SourceEventInterfaceGuid;
// connect to the event source
ATLASSERT(m_Cookie==0); // should not already be connected
if(!SUCCEEDED(AtlAdvise(m_spSourceDispatch,
spUnknown,m_SourceEventInterfaceGuid,&m_Cookie)))
{
throw std::exception();
}
}
void CEventSink::Disconnect()
{
// disconnect from the event source
ATLASSERT(m_Cookie!=0); // should be connected
if(!SUCCEEDED(AtlUnadvise(
m_spSourceDispatch,m_SourceEventInterfaceGuid,m_Cookie)))
{
throw std::exception();
}
m_Cookie=0; // prevent multiple disconnections
}
STDMETHODIMP CEventSink::GetIDsOfNames(
REFIID,OLECHAR FAR* FAR*,unsigned int,LCID,DISPID FAR*)
{
IMP_BEGIN
// unexpected
throw CHResult(E_UNEXPECTED);
// todo : check this is a valid return value
IMP_END
return RetVal;
}
STDMETHODIMP CEventSink::GetTypeInfo(unsigned int,LCID,ITypeInfo FAR* FAR*)
{
IMP_BEGIN
// unexpected
throw CHResult(E_UNEXPECTED);
// todo : check this is a valid return value
IMP_END
return RetVal;
}
STDMETHODIMP CEventSink::GetTypeInfoCount(unsigned int FAR*)
{
IMP_BEGIN
// unexpected
throw CHResult(E_UNEXPECTED);
// todo : check this is a valid return value
IMP_END
return RetVal;
}
STDMETHODIMP CEventSink::Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr)
{
IMP_BEGIN
// check parameters
if(riid!=IID_NULL)
{
throw CHResult(DISP_E_UNKNOWNINTERFACE);
}
if(wFlags!=DISPATCH_METHOD)
{
throw CHResult(E_UNEXPECTED);
// todo : check this is a valid return value
}
if(pDispParams==NULL)
{
throw CHResult(E_POINTER);
// todo : check this is a valid return value
}
// a) lcid can be ignored
// b) pVarResult is dealt with later
// c) pExcepInfo and puArgErr can be ignored if we do not return
// DISP_E_EXCEPTION, DISP_E_TYPEMISMATCH or DISP_E_PARAMNOTFOUND
// process the event
ProcessEvent(dispIdMember,pDispParams,
(pVarResult!=NULL) ? pVarResult : &CComVariant());
IMP_END
return RetVal;
}