POINTS.CPP (LINES OLE Sample)

/*************************************************************************

  • OLE Automation Points object

  • points.cpp

  • CPoints collection implementation

  • Written by Microsoft Product Support Services, Windows Developer Support

  • (c) Copyright Microsoft Corp. 1993 All Rights Reserved

  • ***********************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

#include <ole2.h>

#include <compobj.h>

#include <dispatch.h>

#include <variant.h>

#include <olenls.h>

#endif

#include "lines.h"

/*

* CPoints::Create

*

* Purpose:

* Creates an instance of a collection object and initializes it.

*

* Parameters:

* lMaxSize Maximum number of items that can added to collection.

* lLBound Lower bound of index of collection.

* pPane Pointer to pane that contains this collection. Required because the pane coordinates

* the lines and points collection.

* ppPoints Returns collection object.

*

* Return Value:

* HRESULT

*

*/

HRESULT

CPoints::Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CPoints FAR* FAR* ppPoints)

{

HRESULT hr;

CPoints FAR* pPoints = NULL;

SAFEARRAYBOUND sabound[1];

*ppPoints = NULL;

// Create new collection

pPoints = new CPoints();

if (pPoints == NULL)

goto error;

pPoints->m_cMax = lMaxSize;

pPoints->m_cElements = 0;

pPoints->m_lLBound = lLBound;

pPoints->m_pPane = pPane;

// Load type information for the points collection from type library.

hr = LoadTypeInfo(&pPoints->m_ptinfo, IID_IPoints);

if (FAILED(hr))

goto error;

// Create a safe array which is used to implement the collection.

sabound[0].cElements = lMaxSize;

sabound[0].lLbound = lLBound;

pPoints->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);

if (pPoints->m_psa == NULL)

{

hr = ResultFromScode(E_OUTOFMEMORY);

goto error;

}

*ppPoints = pPoints;

return NOERROR;

error:

if (pPoints == NULL)

return ResultFromScode(E_OUTOFMEMORY);

if (pPoints->m_ptinfo)

pPoints->m_ptinfo->Release();

if (pPoints->m_psa)

SafeArrayDestroy(pPoints->m_psa);

pPoints->m_psa = NULL;

pPoints->m_ptinfo = NULL;

delete pPoints;

return hr;

}

/*

* CPoints::CPoints

*

* Purpose:

* Constructor for CPoints object. Initializes members to NULL.

*

*/

#pragma warning (disable : 4355)

CPoints::CPoints() : m_SupportErrorInfo(this, IID_IPoints)

#pragma warning (default : 4355)

{

m_cRef = 0;

m_psa = NULL;

m_ptinfo = NULL;

}

/*

* CPoints::~CPoints

*

* Purpose:

* Destructor for CPoints object.

*

*/

CPoints::~CPoints()

{

if (m_ptinfo) m_ptinfo->Release();

if (m_psa) SafeArrayDestroy(m_psa);

}

/*

* CPoints::QueryInterface, AddRef, Release

*

* Purpose:

* Implements IUnknown::QueryInterface, AddRef, Release

*

*/

STDMETHODIMP

CPoints::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

*ppv = NULL;

if (iid == IID_IUnknown || iid == IID_IPoints || iid == IID_IDispatch)

*ppv = this;

else if (iid == IID_ISupportErrorInfo)

*ppv = &m_SupportErrorInfo;

else return ResultFromScode(E_NOINTERFACE);

AddRef();

return NOERROR;

}

STDMETHODIMP_(ULONG)

CPoints::AddRef(void)

{

#ifdef _DEBUG

TCHAR ach[50];

wsprintf(ach, TEXT("Ref = %ld, Points\r\n"), m_cRef+1);

OutputDebugString(ach);

#endif

return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CPoints::Release(void)

{

#ifdef _DEBUG

TCHAR ach[50];

wsprintf(ach, TEXT("Ref = %ld, Points\r\n"), m_cRef-1);

OutputDebugString(ach);

#endif

if(--m_cRef == 0)

{

delete this;

return 0;

}

return m_cRef;

}

/*

* CPoints::GetTypeInfoCount

*

* Purpose:

* Implements IDispatch::GetTypeInfoCount.

*

*/

STDMETHODIMP

CPoints::GetTypeInfoCount(UINT FAR* pctinfo)

{

*pctinfo = 1;

return NOERROR;

}

/*

* CPoints::GetTypeInfo

*

* Purpose:

* Implements IDispatch::GetTypeInfo.

*

*/

STDMETHODIMP

CPoints::GetTypeInfo(

UINT itinfo,

LCID lcid,

ITypeInfo FAR* FAR* pptinfo)

{

*pptinfo = NULL;

if(itinfo != 0)

return ResultFromScode(DISP_E_BADINDEX);

m_ptinfo->AddRef();

*pptinfo = m_ptinfo;

return NOERROR;

}

/*

* CPoints::GetIDsOfNames

*

* Purpose:

* Implements IDispatch::GetIDsOfNames. The standard implementation, DispGetIDsOfNames,

* is used.

*

*/

STDMETHODIMP

CPoints::GetIDsOfNames(

REFIID riid,

OLECHAR FAR* FAR* rgszNames,

UINT cNames,

LCID lcid,

DISPID FAR* rgdispid)

{

return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

* CPoints::Invoke

*

* Purpose:

* Implements IDispatch::Invoke. The standard implementation, DispInvoke,

* is used. Properties and methods exposed by the points object will

* set m_bRaiseException to raise an exception.

*

*/

STDMETHODIMP

CPoints::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

WORD wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* puArgErr)

{

HRESULT hr;

m_bRaiseException = FALSE;

hr = DispInvoke(

this, m_ptinfo,

dispidMember, wFlags, pdispparams,

pvarResult, pexcepinfo, puArgErr);

if (m_bRaiseException)

{

if (NULL != pexcepinfo)

_fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

return ResultFromScode(DISP_E_EXCEPTION);

}

else return hr;

}

/*

* CPoints::get_Count

*

* Purpose:

* Returns number of items in collection.

*

*/

STDMETHODIMP

CPoints::get_Count(long FAR* plCount)

{

*plCount = m_cElements;

return NOERROR;

}

/*

* CPoints::get_Item

*

* Purpose:

* Retrieves item from collection, given an index.

*

* Parameters:

* lIndex Index of item to be retrieved.

*

* Returns

* IDispatch of item retrieved from collection.

*

*/

STDMETHODIMP

CPoints::get_Item(long lIndex, IPoint FAR* FAR* ppPoint)

{

HRESULT hr;

VARIANT v;

LPDISPATCH pdisp = NULL;

// Check if integer index is within range

if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements))

return RaiseException(IDS_InvalidIndex);

// Retrieve and return item. Note that SafeArrayGetElement AddRefs so an additional AddRef

// is not required.

VariantInit(&v);

hr = SafeArrayGetElement(m_psa, &lIndex, &v);

if (FAILED(hr))

return RaiseException(IDS_Unexpected);

*ppPoint = (IPoint FAR*) V_DISPATCH(&v);

return NOERROR;

}

/*

* CPoints::get_NewEnum

*

* Purpose:

* Returns an enumerator (IEnumVARIANT) for the items curently in the collection.

* The NewEnum property is restricted and so is invisible to users of an

* automation controller's scripting language. Automation controllers that support

* a 'For Each' statement to iterate through the elements of a collection will use

* the enumerator returned by NewEnum. The enumerator creates a snapshot of the

* the current state of the collection.

*

*/

STDMETHODIMP

CPoints::get__NewEnum(IUnknown FAR* FAR* ppunkEnum)

{

CEnumVariant FAR* penum = NULL;

HRESULT hr;

// Create new enumerator for items currently in collection and QI for IUnknown

hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

if (FAILED(hr))

{hr = RaiseException(IDS_OutOfMemory); goto error;}

hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)ppunkEnum);

if (FAILED(hr))

{hr = RaiseException(IDS_Unexpected); goto error;}

return NOERROR;

error:

if (penum)

delete penum;

return hr;

}

/*

*

* The following methods are not exposed through Automation

*

*/

/*

* CPoints::Add

*

* Purpose:

* Adds an item to the collection. The points collection does not have duplicates.

*

* Parameters:

* pPointAdd Point to be added to collection.

*

*/

STDMETHODIMP_(BOOL)

CPoints::Add(CPoint FAR* pPointAdd)

{

HRESULT hr;

LONG l;

VARIANT v;

VARIANT HUGEP *pvar;

int nX, nY;

BOOL bFound = FALSE;

LPDISPATCH pdispPointAdd = NULL;

CPoint FAR *pPoint;

LPDISPATCH pdispPoint;

// Is the collection full?

if (m_cElements == m_cMax)

goto error;

// Get coordinates of point to be added to collection

nX = pPointAdd->get_x();

nY = pPointAdd->get_y();

hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

if (FAILED(hr))

goto error;

// Check if point to be added is already in the collection.

for (l=0; l<(long)m_cElements; l++)

{

pdispPoint = V_DISPATCH(&pvar[l]);

hr = pdispPoint->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

if (FAILED(hr))

continue;

if (nX == pPoint->get_x() && nY == pPoint->get_y())

{

// Point is already in the collection. AddRef it.

// Internal AddRef keeps track of number of times this point was added to this collection. When

// this internal ref count drops to 0, this point can be removed from this collection.

pPoint->InternalAddRef();

pdispPoint->AddRef();

bFound = TRUE;

pPoint->Release();

break;

}

pPoint->Release();

}

hr = SafeArrayUnaccessData(m_psa);

if (FAILED(hr))

goto error;

// Add point if it was not in the collection.

if (!bFound)

{

l = m_lLBound+m_cElements;

hr = pPointAdd->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdispPointAdd);

if (FAILED(hr))

goto error;

VariantInit(&v);

V_VT(&v) = VT_DISPATCH;

V_DISPATCH(&v) = pdispPointAdd;

hr = SafeArrayPutElement(m_psa, &l, &v);

if (FAILED(hr))

goto error;

// Internal AddRef keeps track of number of times this point was added to this collection. When

// this internal ref count drops to 0, this point can be removed from this collection.

pPointAdd->InternalAddRef();

pdispPointAdd->Release();

m_cElements++;

}

return TRUE;

error:

if (pdispPointAdd)

pdispPointAdd->Release();

return FALSE;

}

/*

* CPoints::Remove

*

* Purpose:

* Removes specified item from collection. The points collection does not have duplicates.

*

* Parameters:

* pPointRemove Point to be removed from collection.

*

*/

STDMETHODIMP_(BOOL)

CPoints::Remove(CPoint FAR* pPointRemove)

{

HRESULT hr;

long l, lIndex;

VARIANT HUGEP *pvar;

ULONG cRef;

int nX, nY;

CPoint FAR* pPoint = NULL;

BOOL bFound = FALSE;

BOOL bRet = FALSE;

// Get coordinates of point to be removed from collection

nX = pPointRemove->get_x();

nY = pPointRemove->get_y();

hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

if (FAILED(hr))

goto error;

// Check if point to be removed is in the collection.

for (l=0; l<(long)m_cElements; l++)

{

hr = V_DISPATCH(&pvar[l])->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

if (FAILED(hr))

continue;

if (nX == pPoint->get_x() && nY == pPoint->get_y())

{

// Release point. Note that this collection does not have duplicates. Duplicate

// points are handled by increasing the ref count.

V_DISPATCH(&pvar[l])->Release();

cRef = pPoint->InternalRelease();

bFound = TRUE;

lIndex = l;

pPoint->Release();

break;

}

pPoint->Release();

}

// If the internal ref count of point to be removed has dropped to 0, move up the array elements

// after the element to be removed.

if (bFound && cRef == 0)

{

for (l=lIndex; l<(long)(m_cElements-1); l++)

pvar[l] = pvar[l+1];

// Remove last element.

V_VT(&pvar[l]) = VT_EMPTY;

m_cElements--;

bRet = TRUE;

}

hr = SafeArrayUnaccessData(m_psa);

if (FAILED(hr))

goto error;

return bRet;

error:

return FALSE;

}

/*

* CPoints::Clear

*

* Purpose:

* Removes all items from collection.

*

*/

STDMETHODIMP_(void)

CPoints::Clear(void)

{

SafeArrayDestroyData(m_psa);

SafeArrayAllocData(m_psa);

m_cElements = 0;

}

/*

* CPoints::GetMaxXMaxY

*

* Purpose:

* Get the maximum X and Y coordinates that are in the rectangle, prc.

*

*/

STDMETHODIMP_(void)

CPoints::GetMaxXMaxY(int FAR *pnX, int FAR *pnY, LPRECT prc)

{

HRESULT hr;

long l;

VARIANT HUGEP *pvar;

int nMaxX, nMaxY;

CPoint FAR* pPoint;

POINT pt;

hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

if (FAILED(hr))

return;

nMaxX = -1; nMaxY = -1;

// Find the maximume X and Y coordinates that are in the prc rectangle.

for (l=0; l<(long)m_cElements; l++)

{

V_DISPATCH(&pvar[l])->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

pt.x = pPoint->get_x();

pt.y = pPoint->get_y();

if (PtInRect(prc, pt))

{

if (pt.x > nMaxX)

nMaxX = pt.x;

if (pt.y > nMaxY)

nMaxY = pt.y;

}

pPoint->Release();

}

*pnX = nMaxX;

*pnY = nMaxY;

SafeArrayUnaccessData(m_psa);

return;

}

/*

* CPoints::RaiseException

*

* Purpose:

* Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

* Sets ErrorInfo object for vtable-binding controllers.

*

*/

STDMETHODIMP

CPoints::RaiseException(int nID)

{

extern SCODE g_scodes[];

TCHAR szError[STR_LEN];

ICreateErrorInfo *pcerrinfo;

IErrorInfo *perrinfo;

HRESULT hr;

_fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

m_excepinfo.wCode = nID;

if (LoadString(g_pApplication->m_hinst, nID, szError, sizeof(szError)))

m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

m_excepinfo.bstrSource = SysAllocString(g_pApplication->m_bstrProgID);

m_bRaiseException = TRUE;

// Set ErrInfo object so that vtable binding containers can get

// rich error information.

hr = CreateErrorInfo(&pcerrinfo);

if (SUCCEEDED(hr))

{

pcerrinfo->SetGUID(IID_IPoints);

if (m_excepinfo.bstrSource)

pcerrinfo->SetSource(m_excepinfo.bstrSource);

if (m_excepinfo.bstrDescription)

pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

if (SUCCEEDED(hr))

{

SetErrorInfo(0, perrinfo);

perrinfo->Release();

}

pcerrinfo->Release();

}

return ResultFromScode(g_scodes[nID-1001]);

}

Software for developers
Delphi Components
.Net Components
Software for Android Developers
More information resources
MegaDetailed.Net
Unix Manual Pages
Delphi Examples