CPOINT.CPP

/***  
*cpoint.cpp
*
* This is a part of the Microsoft Source Code Samples.
*
* Copyright 1992 - 1998 Microsoft Corporation. All rights reserved.
*
* This source code is only intended as a supplement to Microsoft Development
* Tools and/or WinHelp documentation. See these sources for detailed
* information regarding the Microsoft samples programs.
*
*Purpose:
* This module implements the CPoint and CPointCF classes.
*
* This module is intended as a sample implementation of the IDispatch
* interface, and its purpose is to demonstrate how an object can
* expose methods and properties for programatic and cross-process
* access via the IDispatch interface.
*
*Implementation Notes:
*
*****************************************************************************/

#include "spoly.h"
#include "cpoint.h"


CPoint::CPoint()
{
m_x = 0;
m_y = 0;
m_refs = 0;
}

/***
*CPoint::Create(void)
*Purpose:
* Create an instance of a CPoint object.
*
*Entry:
* None
*
*Exit:
* returns a CPoint*, NULL if creation failed.
*
***********************************************************************/
CPoint FAR*
CPoint::Create()
{
CPoint FAR* ppoint;

if((ppoint = new FAR CPoint()) == NULL)
return NULL;
ppoint->AddRef();
return ppoint;
}


//---------------------------------------------------------------------
// IUnknown Methods
//---------------------------------------------------------------------


STDMETHODIMP
CPoint::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
if(!IsEqualIID(riid, IID_IUnknown))
if(!IsEqualIID(riid, IID_IDispatch)) {
*ppv = NULL;
return E_NOINTERFACE;
}

*ppv = this;
AddRef();
return NOERROR;
}


STDMETHODIMP_(unsigned long)
CPoint::AddRef(void)
{
return ++m_refs;
}


STDMETHODIMP_(unsigned long)
CPoint::Release(void)
{
if(--m_refs == 0){
delete this;
return 0;
}
return m_refs;
}


//---------------------------------------------------------------------
// IDispatch methods
//---------------------------------------------------------------------

/*
* NOTE: Support for the following two methods is not available
* in this version.
*
*/

STDMETHODIMP
CPoint::GetTypeInfoCount(unsigned int FAR* pctinfo)
{
*pctinfo = 0;
return NOERROR;
}


STDMETHODIMP
CPoint::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
UNUSED(itinfo);
UNUSED(lcid);
UNUSED(pptinfo);

return E_NOTIMPL;
}


/***
*HRESULT CPoint::GetIDsOfNames(REFIID, OLECHAR**, unsigned int, LCID, long*)
*Purpose:
* This method translates the given array of names to a corresponding
* array of DISPIDs.
*
* Index 0 of the name array is the member name, and indices 1-N if
* present represent named parameters on that member.
*
* The local ID ('lcid') is unused by this naive implementation. A more
* sophisticated implementation, sensitive to localization and natural
* language support would use the locale ID to interpret the given names
* in a correct locale specific context.
*
*Entry:
* rgszNames = pointer to an array of names
* cNames = the number of names in the rgszNames array
* lcid = the callers locale ID
*
*Exit:
* return value = HRESULT
* rgid = array of name IDs corresponding to the rgszNames array
* this array will contain -1 for each entry that is not known.
*
***********************************************************************/
STDMETHODIMP
CPoint::GetIDsOfNames(
REFIID riid,
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
LCID lcid,
DISPID FAR* rgdispid)
{
static MEMBERDESC rgmdCPoint[] = {
{OLESTR("GETX"),IDMEMBER_CPOINT_GETX,NULL,0},
{OLESTR("SETX"),IDMEMBER_CPOINT_SETX,NULL,0},
{OLESTR("GETY"),IDMEMBER_CPOINT_GETY,NULL,0},
{OLESTR("SETY"),IDMEMBER_CPOINT_SETY,NULL,0}
};

// this object only exposed the "default" interface.
//
if(!IsEqualIID(riid, IID_NULL))
return DISP_E_UNKNOWNINTERFACE;

return SPolyGetIDsOfNames(
rgmdCPoint, DIM(rgmdCPoint), rgszNames, cNames, lcid, rgdispid);
}


/***
*HRESULT CPoint::Invoke(...)
*Purpose:
* Dispatch a method or property request for objects of type CPoint.
*
* see the IDispatch document for more information, and a general
* description of this method.
*
*Entry:
* dispidMember = the DISPID of the member being requested
*
* riid = reference to the interface ID of the interface on this object
* that the requested member belongs to. IID_NULL means to interpret
* the member as belonging to the implementation defined "default"
* or "primary" interface.
*
* lcid = the caller's locale ID
*
* wFlags = flags indicating the type of access being requested
*
* pdispparams = pointer to the DISPPARAMS struct containing the
* requested members arguments (if any) and its named parameter
* DISPIDs (if any).
*
*Exit:
* return value = HRESULT
* see the IDispatch spec for a description of possible success codes.
*
* pvarResult = pointer to a caller allocated VARIANT containing
* the members return value (if any).
*
* pexcepinfo = caller allocated exception info structure, this will
* be filled in only if an exception was raised that must be passed
* up through Invoke to an enclosing handler.
*
* puArgErr = pointer to a caller allocated UINT, that will contain the
* index of the offending argument if a DISP_E_TYPEMISMATCH error
* was returned indicating that one of the arguments was of an
* incorrect type and/or could not be reasonably coerced to a proper
* type.
*
***********************************************************************/
STDMETHODIMP
CPoint::Invoke(
DISPID dispidMember,
REFIID riid,
LCID lcid,
unsigned short wFlags,
DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo,
unsigned int FAR* puArgErr)
{
unsigned int uArgErr;
HRESULT hresult;
VARIANTARG varg0;
VARIANT varResultDummy;

UNUSED(lcid);
UNUSED(pexcepinfo);

// make sure the wFlags are legal
if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
return E_INVALIDARG;

// this object only exposes a "default" interface.
//
if(!IsEqualIID(riid, IID_NULL))
return DISP_E_UNKNOWNINTERFACE;

// this makes the following code a bit simpler
if(puArgErr == NULL)
puArgErr = &uArgErr;
if(pvarResult == NULL)
pvarResult = &varResultDummy;

VariantInit(&varg0);

// assume the return type is void, unless we find otherwise.
VariantInit(pvarResult);

switch(dispidMember){
case IDMEMBER_CPOINT_GETX:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = GetX();
break;

case IDMEMBER_CPOINT_SETX:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
SetX(V_I2(&varg0));
break;

case IDMEMBER_CPOINT_GETY:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = GetY();
break;

case IDMEMBER_CPOINT_SETY:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
SetY(V_I2(&varg0));
break;

default:
return DISP_E_MEMBERNOTFOUND;
}
return NOERROR;
}

short PASCAL
CPoint::GetX()
{
return m_x;
}

void PASCAL
CPoint::SetX(short x)
{
m_x = x;
}

short PASCAL
CPoint::GetY()
{
return m_y;
}

void PASCAL
CPoint::SetY(short y)
{
m_y = y;
}


//---------------------------------------------------------------------
// Implementation of the CPoint Class Factory
//---------------------------------------------------------------------

CPointCF::CPointCF()
{
m_refs = 0;
}

IClassFactory FAR*
CPointCF::Create()
{
CPointCF FAR* pCF;

if((pCF = new FAR CPointCF()) == NULL)
return NULL;
pCF->AddRef();
return pCF;
}

STDMETHODIMP
CPointCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{

if(!IsEqualIID(riid, IID_IUnknown))
if(!IsEqualIID(riid, IID_IClassFactory)) {
*ppv = NULL;
return E_NOINTERFACE;
}

*ppv = this;
++m_refs;
return NOERROR;
}

STDMETHODIMP_(unsigned long)
CPointCF::AddRef(void)
{
return ++m_refs;
}

STDMETHODIMP_(unsigned long)
CPointCF::Release(void)
{
if(--m_refs == 0){
delete this;
return 0;
}
return m_refs;
}

STDMETHODIMP
CPointCF::CreateInstance(
IUnknown FAR* punkOuter,
REFIID riid,
void FAR* FAR* ppv)
{
HRESULT hresult;
CPoint FAR *ppoint;

UNUSED(punkOuter);

if((ppoint = CPoint::Create()) == NULL){
*ppv = NULL;
return E_OUTOFMEMORY;
}
hresult = ppoint->QueryInterface(riid, ppv);
ppoint->Release();
return hresult;
}

STDMETHODIMP
#ifdef _MAC
CPointCF::LockServer(unsigned long fLock)
#else
CPointCF::LockServer(BOOL fLock)
#endif
{
UNUSED(fLock);

return NOERROR;
}