/*
*********************************************************************
*
*	The Essence of OLE
*
*	Source code sample
*
*	Copyright (c) 1996, Rolling Thunder Computing, Ipswich MA
*
*	e-mail: essence@rollthunder.com
*	CompuServe: 73540,3430
*	Web: http://www.rollthunder.com
*
*	File Name: HELLO.CPP
*
*	Purpose: OLE Automation object that implements IDispatch
*
*********************************************************************
*/

#include "resource.h"
#include "hellodisp.h"       
					

extern HWND hMainWnd ;

/*
Class Constructor/destructor
*/

CAggrHelloDispatch::CAggrHelloDispatch(IUnknown * pUnkOuter)
{
	m_RefCount = 1;

/*
Remember the outer IUnknown. It will be NULL if we are being created
standalone and non-NULL if we are being aggregated. Do NOT AddRef( ) 
this pointer. That would give us an interlocking reference situation.
*/

	m_pUnkOuter = pUnkOuter ;

/*
Tell the delegating unknown who to delegate to. If we are aggregated,
it will be the outer IUnknown. Otherwise it will be out own
internal non-delegating IUnknown.
*/
	if (m_pUnkOuter)
	{
		m_DelegatingDispatch.m_pGuyToDelegateTo = m_pUnkOuter ;
	}
	else
	{
		m_DelegatingDispatch.m_pGuyToDelegateTo =	this ;
	}
}


CAggrHelloDispatch::~CAggrHelloDispatch()
{
	PostQuitMessage(0);
}



static const GUID IID_IDHello = { 0x6ced2902, 0xa1dd, 0x11cf, 
	{ 0x8a, 0x33, 0x0, 0xaa, 0x0, 0xa5, 0x80, 0x97 } };

STDMETHODIMP CAggrHelloDispatch::QueryInterface(REFIID riid, void **ppv)
{
	if (riid == IID_IUnknown)
	{
		*ppv = this ;
		AddRef( ) ;
		return S_OK ;
	}
	else if (riid == IID_IDispatch)
	{
		*ppv = &m_DelegatingDispatch ;
		m_DelegatingDispatch.AddRef( ) ;
		return S_OK ;
	}

	return S_OK ;
}


STDMETHODIMP_(ULONG) CAggrHelloDispatch::AddRef()
{
	return ++m_RefCount ;
}

STDMETHODIMP_(ULONG) CAggrHelloDispatch::Release()
{
    if(--m_RefCount == 0)
	{
		delete this;
		return 0;
	}
	return m_RefCount;
}


STDMETHODIMP CAggrHelloDispatch::CDelegatingDispatch::QueryInterface(REFIID riid, void **ppv)
{
	return m_pGuyToDelegateTo->QueryInterface (riid, ppv) ;
}


STDMETHODIMP_(ULONG) CAggrHelloDispatch::CDelegatingDispatch::AddRef()
{
	return m_pGuyToDelegateTo->AddRef ( ) ;
}

STDMETHODIMP_(ULONG) CAggrHelloDispatch::CDelegatingDispatch::Release()
{
	return m_pGuyToDelegateTo->Release ( ) ;
}

        
/*
STEP 2
GetIDsOfNames( ) method.  Caller is asking for the dispatch IDs that correspond
to the names of the specified items.  Compare the requested name with the ones
that we support.  If found, place the integer ID in the output parameter and
return success, otherwise return an error code.
*/

STDMETHODIMP CAggrHelloDispatch::CDelegatingDispatch::GetIDsOfNames(REFIID riid, LPOLESTR *pNames,
	UINT cNames, LCID lcid, DISPID *pDispID)
{
	if (_wcsicmp (*pNames, L"SayHello") == 0)
	{
		*pDispID = 2 ;
		return NOERROR ;
	}
	else if (_wcsicmp (*pNames, L"HelloMessage") == 0)
	{
		*pDispID = 1 ;
		return NOERROR ;
	}

	return DISP_E_UNKNOWNNAME ;
}

/*
IDispatch::Invoke( ) method.  Caller is telling us to do something,
either call a method or set or get the value of a property. Decode 
parameters and take requested action.
*/

STDMETHODIMP CAggrHelloDispatch::CDelegatingDispatch::Invoke(DISPID dispidMember, REFIID riid,
	LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
	VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
	
/*
Caller wants to get or set the HelloMessage property.
*/
	if (dispidMember == 1)
	{
/*
STEP 3
Check the wFlags element for DISPATCH_PROPERTYGET.  If found, the caller
is trying to get the HelloMessage property. Set the vt element of the
pVarResult parameter to the proper value to indicate a string. Use the
function SysAllocString( ) to allocate a new BSTR containing the string in
the member variable m_bstrHelloMsg. Place this BSTR in the return variant
and return the success code.
*/
		if (wFlags & DISPATCH_PROPERTYGET)						   	
		{
			if (pDispParams->cArgs != 0)
			{
				return DISP_E_BADPARAMCOUNT ;
			}

			pVarResult->vt = VT_BSTR ;
			pVarResult->bstrVal = SysAllocString(m_bstrHelloMsg);
		}

/*
STEP 4
Check the wFlags element for DISPATCH_PROPERTYPUT.  If found, the caller
is trying to set the HelloMessage property. Check the vt element of the 
supplied variant to make sure it contains a BSTR.  If so, use the 
function SysReAllocString( ) to reset the value of the member variable
m_bstrHelloMsg to the new value supplied in the VARIANT. Return success
or failure code.
*/

		else if (wFlags & DISPATCH_PROPERTYPUT)
		{
			if (pDispParams->cArgs != 1)
			{
				return DISP_E_BADPARAMCOUNT ;
			}


/*
STEP 5
Perform type checking on the passed VARIANT.  If not ablt to be coerced 
into a  BSTR, then fill EXCEPINFO structure and return the failure code 
that says the EXCEPINFO contains valid information.
*/
			
			if (pDispParams->rgvarg[0].vt != VT_BSTR)
			{
				pExcepInfo->wCode = 0 ;
				pExcepInfo->wReserved = 0 ;
				pExcepInfo->pvReserved = NULL ;
				pExcepInfo->pfnDeferredFillIn = NULL ;

				pExcepInfo->bstrSource = SysAllocString (L"Hello32.exe") ;
				pExcepInfo->bstrDescription = SysAllocString (L"Expecting string parameter") ;
				pExcepInfo->scode = DISP_E_TYPEMISMATCH ;
				
				pExcepInfo->bstrHelpFile = SysAllocString (L"hello32.hlp") ;
				pExcepInfo->dwHelpContext = 1 ;

				return DISP_E_EXCEPTION ;
			}

			SysReAllocString(&m_bstrHelloMsg, pDispParams->rgvarg[0].bstrVal);
		}
		return NOERROR ;

	}

/*
Caller wants to output the current message in the box
*/

	else if (dispidMember == 2)
	{
		if (pDispParams->cArgs != 0)
		{
			return DISP_E_BADPARAMCOUNT ;
		}

		MessageBeep (0) ;
		char out [128] ;
		WideCharToMultiByte (CP_ACP, 0, m_bstrHelloMsg, SysStringByteLen(m_bstrHelloMsg), out, sizeof(out), NULL, NULL) ; 
		SetDlgItemText(hMainWnd, IDC_HELLOAREA, out);
		return NOERROR ;
	}

	return DISP_E_MEMBERNOTFOUND ;
}


/*
Unimplemented methods of IDispatch.
*/


STDMETHODIMP CAggrHelloDispatch::CDelegatingDispatch::GetTypeInfoCount(UINT *pNtypeInfo)
{
	*pNtypeInfo = 0;
	return E_NOTIMPL ;
}
        
STDMETHODIMP CAggrHelloDispatch::CDelegatingDispatch::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
{
	*pptinfo = NULL ;	
	return E_NOTIMPL ;
}

