CONTROL.CPP

/* 
* CONTROL.CPP
* Polyline Chapter 24
*
* Additional interfaces above the Chapter 23 version of Polyline
* to make it an OLE Control, specifically ISpecifyPropertyPages,
* IProvideClassInfo, IOleControl, and IDispatch, none of which
* are terribly complex.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/


#include "polyline.h"


//ISpecifyPropertyPages implementation
/*
* CImpISpecifyPP::CImpISpecifyPP
* CImpISpecifyPP::~CImpISpecifyPP
*
* Parameters (Constructor):
* pObj PCPolyline of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/

CImpISpecifyPP::CImpISpecifyPP(PCPolyline pObj, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}

CImpISpecifyPP::~CImpISpecifyPP(void)
{
return;
}


/*
* CImpISpecifyPP::QueryInterface
* CImpISpecifyPP::AddRef
* CImpISpecifyPP::Release
*/

STDMETHODIMP CImpISpecifyPP::QueryInterface(REFIID riid
, LPVOID *ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}

STDMETHODIMP_(ULONG) CImpISpecifyPP::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CImpISpecifyPP::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}



/*
* CImpISpecifyPP::GetPages
*
* Purpose:
* Returns an array of GUIDs identifying the indivudual property
* pages used for this object.
*
* Parameters:
* pPages CAUUID * pointing to a counted array of GUIDs.
* This function allocates the array elements
* and stores them in this structure.
*/

STDMETHODIMP CImpISpecifyPP::GetPages(CAUUID *pPages)
{
IMalloc *pIMalloc;
GUID *pGUID;

pPages->cElems=0;
pPages->pElems=NULL;

if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
return ResultFromScode(E_OUTOFMEMORY);

pGUID=(GUID *)pIMalloc->Alloc(CPROPPAGES * sizeof(GUID));

if (NULL!=pGUID)
{
//We use our own page plus the standard color page.
pGUID[0]=CLSID_PolylinePropPage;

//Fill the structure and return.
pPages->cElems=CPROPPAGES;
pPages->pElems=pGUID;
}

pIMalloc->Release();
return (NULL!=pGUID) ? NOERROR
: ResultFromScode(E_OUTOFMEMORY);
}




//IProvideClassInfo interface implementation
/*
* CImpIProvideClassInfo::CImpIProvideClassInfo
* CImpIProvideClassInfo::~CImpIProvideClassInfo
*
* Parameters (Constructor):
* pObj PCPolyline of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/

CImpIProvideClassInfo::CImpIProvideClassInfo(PCPolyline pObj
, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}

CImpIProvideClassInfo::~CImpIProvideClassInfo(void)
{
return;
}



/*
* CImpIProvideClassInfo::QueryInterface
* CImpIProvideClassInfo::AddRef
* CImpIProvideClassInfo::Release
*/

STDMETHODIMP CImpIProvideClassInfo::QueryInterface(REFIID riid
, LPVOID *ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}

STDMETHODIMP_(ULONG) CImpIProvideClassInfo::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CImpIProvideClassInfo::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}



/*
* CImpIProvideClassInfo::GetClassInfo
*
* Purpose:
* Returns the ITypeInfo through which the caller can retrieve
* information about the entire object.
*
* Parameters:
* ppTI LPTYPEINFO * in which to store the ITypeInfo
* pointer.
*/

STDMETHODIMP CImpIProvideClassInfo::GetClassInfo(LPTYPEINFO *ppTI)
{
if (NULL==ppTI)
return ResultFromScode(E_POINTER);

*ppTI=NULL;

return m_pObj->m_pITypeLib->GetTypeInfoOfGuid(CLSID_Polyline19
, ppTI);
}




//IDispatch interface implementation

/*
* CImpIDispatch::CImpIDispatch
* CImpIDispatch::~CImpIDispatch
*
* Parameters (Constructor):
* pObj PCPolyline of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/

CImpIDispatch::CImpIDispatch(PCPolyline pObj, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}

CImpIDispatch::~CImpIDispatch(void)
{
return;
}



/*
* CImpIDispatch::QueryInterface
* CImpIDispatch::AddRef
* CImpIDispatch::Release
*/

STDMETHODIMP CImpIDispatch::QueryInterface(REFIID riid, PPVOID ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}


STDMETHODIMP_(ULONG) CImpIDispatch::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CImpIDispatch::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}



/*
* CImpIDispatch::GetTypeInfoCount
* CImpIDispatch::GetTypeInfo
* CImpIDispatch::GetIDsOfNames
*
* The usual
*/

STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
{
//We implement GetTypeInfo so return 1
*pctInfo=1;
return NOERROR;
}


STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itInfo, LCID lcid
, ITypeInfo **ppITypeInfo)
{
if (0!=itInfo)
return ResultFromScode(TYPE_E_ELEMENTNOTFOUND);

if (NULL==ppITypeInfo)
return ResultFromScode(E_POINTER);

*ppITypeInfo=NULL;

//We ignore the LCID
return m_pObj->m_pITypeLib->GetTypeInfoOfGuid
(DIID_DIPolylineControl, ppITypeInfo);
}


STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid
, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
{
HRESULT hr;
ITypeInfo *pTI;

if (IID_NULL!=riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

hr=GetTypeInfo(0, lcid, &pTI);

if (SUCCEEDED(hr))
{
hr=DispGetIDsOfNames(pTI, rgszNames, cNames, rgDispID);
pTI->Release();
}

return hr;
}



/*
* CImpIDispatch::Invoke
*
* Purpose:
* Calls a method in the dispatch interface or manipulates a
* property.
*
* Parameters:
* dispID DISPID of the method or property of interest.
* riid REFIID reserved, must be IID_NULL.
* lcid LCID of the locale.
* wFlags USHORT describing the context of the invocation.
* pDispParams DISPPARAMS * to the array of arguments.
* pVarResult VARIANT * in which to store the result. Is
* NULL if the caller is not interested.
* pExcepInfo EXCEPINFO * to exception information.
* puArgErr UINT * in which to store the index of an
* invalid parameter if DISP_E_TYPEMISMATCH
* is returned.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/

STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid
, LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams
, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
HRESULT hr;
ITypeInfo *pTI;

//riid is supposed to be IID_NULL always
if (IID_NULL!=riid)
return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

//Get the ITypeInfo for lcid
hr=GetTypeInfo(0, lcid, &pTI);

if (FAILED(hr))
return hr;

hr=pTI->Invoke(m_pObj->m_pImpIPolylineControl, dispID, wFlags
, pDispParams, pVarResult, pExcepInfo, puArgErr);

pTI->Release();
return hr;
}



//IPolylineControl interface implementation

/*
* CImpIPolylineControl::CImpIPolylineControl
* CImpIPolylineControl::~CImpIPolylineControl
*
* Parameters (Constructor):
* pObj PCPolyline of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/

CImpIPolylineControl::CImpIPolylineControl(PCPolyline pObj
, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}

CImpIPolylineControl::~CImpIPolylineControl(void)
{
return;
}



/*
* CImpIPolylineControl::QueryInterface
* CImpIPolylineControl::AddRef
* CImpIPolylineControl::Release
*/

STDMETHODIMP CImpIPolylineControl::QueryInterface(REFIID riid
, LPVOID *ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}

STDMETHODIMP_(ULONG) CImpIPolylineControl::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CImpIPolylineControl::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}



/*
* CImpIPolylineControl::BackColor
* CImpIPolylineControl::LineColor
* CImpIPolylineControl::LineStyle
* CImpIPolylineControl::Clear
* CImpIPolylineControl::RemoveLastPoint
*
* Purpose:
* Dispatch interface entry points that map to IPolyline
* members.
*/

STDMETHODIMP_(void) CImpIPolylineControl::put_BackColor
(OLE_COLOR cr)
{
COLORREF crOld;

m_pObj->m_pImpIPolyline->ColorSet(POLYLINECOLOR_BACKGROUND
, cr, &crOld);
return;
}

STDMETHODIMP_(OLE_COLOR) CImpIPolylineControl::get_BackColor(void)
{
COLORREF cr;

m_pObj->m_pImpIPolyline->ColorGet(POLYLINECOLOR_BACKGROUND
, &cr);

return cr;
}

STDMETHODIMP_(void) CImpIPolylineControl::put_LineColor
(OLE_COLOR cr)
{
COLORREF crOld;

m_pObj->m_pImpIPolyline->ColorSet(POLYLINECOLOR_LINE
, cr, &crOld);

return;
}

STDMETHODIMP_(OLE_COLOR) CImpIPolylineControl::get_LineColor(void)
{
COLORREF cr;

m_pObj->m_pImpIPolyline->ColorGet(POLYLINECOLOR_LINE, &cr);
return cr;
}

STDMETHODIMP_(void) CImpIPolylineControl::put_LineStyle
(short iStyle)
{
UINT i;

m_pObj->m_pImpIPolyline->LineStyleSet(iStyle, &i);
return;
}

STDMETHODIMP_(short) CImpIPolylineControl::get_LineStyle(void)
{
UINT iStyle;

m_pObj->m_pImpIPolyline->LineStyleGet(&iStyle);
return (short)iStyle;
}

STDMETHODIMP CImpIPolylineControl::Clear(void)
{
return m_pObj->m_pImpIPolyline->New();
}

STDMETHODIMP CImpIPolylineControl::RemoveLastPoint(void)
{
return m_pObj->m_pImpIPolyline->Undo();
}






//IOleControl interface implementation

/*
* CImpIOleControl::CImpIOleControl
* CImpIOleControl::~CImpIOleControl
*
* Parameters (Constructor):
* pObj PCPolyline of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/

CImpIOleControl::CImpIOleControl(PCPolyline pObj
, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}

CImpIOleControl::~CImpIOleControl(void)
{
return;
}



/*
* CImpIOleControl::QueryInterface
* CImpIOleControl::AddRef
* CImpIOleControl::Release
*/

STDMETHODIMP CImpIOleControl::QueryInterface(REFIID riid
, LPVOID *ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}

STDMETHODIMP_(ULONG) CImpIOleControl::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CImpIOleControl::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}



/*
* CImpIOleControl::GetControlInfo
*
* Purpose:
* Fills a CONTROLINFO structure containing information about
* the controls mnemonics and other behavioral aspects.
*
* Parameters:
* pCI LPCONTROLINFO to the structure to fill
*/

STDMETHODIMP CImpIOleControl::GetControlInfo(LPCONTROLINFO pCI)
{
if (NULL==pCI)
return ResultFromScode(E_INVALIDARG);

*pCI=m_pObj->m_ctrlInfo;
return ResultFromScode(E_NOTIMPL);
}




/*
* CImpIOleControl::OnMnemonic
*
* Purpose:
* Notifies the control that a mnemonic was activated.
*
* Parameters:
* pMsg LPMSG containing the message that matches one of
* the control's mnemonics. The control uses this
* to distinguish which mnemonic was pressed.
*/

STDMETHODIMP CImpIOleControl::OnMnemonic(LPMSG pMsg)
{
//No mnemonics
return NOERROR;
}





/*
* CImpIOleControl::OnAmbientPropertyChange
*
* Purpose:
* Notifies the control that one or more of the container's ambient
* properties changed.
*
* Parameters:
* dispID DISPID identifying the property, which can
* be DISPID_UNKNOWN indicating that more than
* one changed.
*/

STDMETHODIMP CImpIOleControl::OnAmbientPropertyChange(DISPID dispID)
{
/*
* We detect any change in UIDead or ShowHatching. Changes
* in container colors do not affect us as we only use those
* for initial values.
*/

switch (dispID)
{
case DISPID_UNKNOWN:
m_pObj->AmbientsInitialize(INITAMBIENT_SHOWHATCHING
| INITAMBIENT_UIDEAD);
break;

case DISPID_AMBIENT_SHOWHATCHING:
m_pObj->AmbientsInitialize(INITAMBIENT_SHOWHATCHING);
break;

case DISPID_AMBIENT_UIDEAD:
m_pObj->AmbientsInitialize(INITAMBIENT_UIDEAD);
break;
}

return NOERROR;
}




/*
* CImpIOleControl::FreezeEvents
*
* Purpose:
* Instructs the control to stop firing events or to continue
* firing them.
*
* Parameters:
* fFreeze BOOL indicating to freeze (TRUE) or thaw (FALSE)
* events from this control.
*/

STDMETHODIMP CImpIOleControl::FreezeEvents(BOOL fFreeze)
{
m_pObj->m_fFreezeEvents=fFreeze;
return NOERROR;
}






//CAdviseRouter class implementation
/*
* CAdviseRouter::CAdviseRouter
* CAdviseRouter::~CAdviseRouter
*
* Constructor Parameters:
* pIDispatch IDispatch * to which we route notifications.
* pObj PCPolyline to the control itself.
*/

CAdviseRouter::CAdviseRouter(IDispatch *pIDispatch
, PCPolyline pObj)
{
m_cRef=0;
m_pObj=pObj;
m_pIDispatch=pIDispatch;
return;
}


CAdviseRouter::~CAdviseRouter(void)
{
ReleaseInterface(m_pIDispatch);
return;
}




/*
* CAdviseRouter::QueryInterface
* CAdviseRouter::AddRef
* CAdviseRouter::Release
*
* Purpose:
* IUnknown members for this IPolylineAdviseSink implementations.
*/

STDMETHODIMP CAdviseRouter::QueryInterface(REFIID riid
, PPVOID ppv)
{
*ppv=NULL;

if (IID_IUnknown==riid || IID_IPolylineAdviseSink10==riid)
{
*ppv=this;
AddRef();
return NOERROR;
}

return ResultFromScode(E_NOINTERFACE);
}


STDMETHODIMP_(ULONG) CAdviseRouter::AddRef(void)
{
return ++m_cRef;
}


STDMETHODIMP_(ULONG) CAdviseRouter::Release(void)
{
if (0L!=--m_cRef)
return m_cRef;

delete this;
return 0;
}




/*
* CAdviseRouter::OnPointChange
* CAdviseRouter::OnSizeChange
* CAdviseRouter::OnColorChange
* CAdviseRouter::OnLineStyleChange
*
* Purpose:
* Invokes the same member in the IDispatch pointer we hold.
*/

STDMETHODIMP_(void) CAdviseRouter::OnPointChange(void)
{
Invoke(EVENT_ONPOINTCHANGE);
return;
}

STDMETHODIMP_(void) CAdviseRouter::OnSizeChange(void)
{
Invoke(EVENT_ONSIZECHANGE);
return;
}


STDMETHODIMP_(void) CAdviseRouter::OnColorChange(void)
{
Invoke(EVENT_ONCOLORCHANGE);
return;
}


STDMETHODIMP_(void) CAdviseRouter::OnLineStyleChange(void)
{
Invoke(EVENT_ONLINESTYLECHANGE);
return;
}




/*
* CAdviseRouter::Invoke
*
* Purpose:
* Calls IDispatch::Invoke for any of the events we handle.
* None of these have any arguments.
*
* Parameters:
* dispID DISPID of the event to fire.
*
* Return Value:
* None
*/

void CAdviseRouter::Invoke(DISPID dispID)
{
DISPPARAMS dp;
VARIANT va;

if (m_pObj->m_fFreezeEvents)
return;

m_pIDispatch->Invoke(dispID, IID_NULL
, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp
, &va, NULL, NULL);

return;
}