/*** *CPoly.cpp * * Copyright (C) 1992-1994, Microsoft Corporation. All Rights Reserved. * *Purpose: * This module implements the CPoly and CPolyCF 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" #include "cpoly.h" #include "cenumpt.h" #ifndef _MAC extern CStatBar FAR* g_psb; #else extern "C" WindowPtr g_pwndClient; #endif // our global list of polygons. // POLYLINK FAR* g_ppolylink = (POLYLINK FAR*)NULL; // global count of polygons. // int g_cPoly = 0; CPoly::CPoly() { m_refs = 0; m_xorg = 0; m_yorg = 0; m_width = 0; m_cPoints = 0; m_red = 0; m_green = 0; m_blue = 0; m_ppointlink = NULL; m_ppointlinkLast = NULL; } /*** *CPoly *CPoly::Create(void) *Purpose: * Create an instance of a CPoly object, and add it to the global * list of polygons. * *Entry: * None * *Exit: * returns a polygon object, NULL the allocation failed. * ***********************************************************************/ CPoly FAR* CPoly::Create() { CPoly FAR* ppoly; POLYLINK FAR* ppolylink; if((ppolylink = new FAR POLYLINK) == (POLYLINK FAR*)NULL) return (CPoly FAR*)NULL; if((ppoly = new FAR CPoly()) == (CPoly FAR*)NULL) return (CPoly FAR*)NULL; ppoly->AddRef(); // push the new polygon onto the front of the polygon list. // ++g_cPoly; ppolylink->ppoly = ppoly; ppolylink->next = g_ppolylink; g_ppolylink = ppolylink; #ifndef _MAC SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly); #endif return ppoly; } //--------------------------------------------------------------------- // IUnknown Methods //--------------------------------------------------------------------- STDMETHODIMP CPoly::QueryInterface(REFIID riid, void FAR* FAR* ppv) { if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch)) { *ppv = this; AddRef(); return NOERROR; } *ppv = NULL; return ResultFromScode(E_NOINTERFACE); } STDMETHODIMP_(unsigned long) CPoly::AddRef() { return ++m_refs; } STDMETHODIMP_(unsigned long) CPoly::Release() { POLYLINK FAR* FAR* pppolylink, FAR* ppolylinkDead; if(--m_refs == 0){ Reset(); // release all CPoints // remove ourselves from the global list of polygons // for( pppolylink = &g_ppolylink; *pppolylink != NULL; pppolylink = &(*pppolylink)->next) { if((*pppolylink)->ppoly == this){ ppolylinkDead = *pppolylink; *pppolylink = (*pppolylink)->next; delete ppolylinkDead; break; } } --g_cPoly; #ifndef _MAC SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly); #endif delete this; return 0; } return m_refs; } //--------------------------------------------------------------------- // IDispatch Methods //--------------------------------------------------------------------- /* * NOTE: Support for the following two methods is not available * in this version. * */ STDMETHODIMP CPoly::GetTypeInfoCount(unsigned int FAR* pctinfo) { *pctinfo = 0; return NOERROR; } STDMETHODIMP CPoly::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) { UNUSED(itinfo); UNUSED(lcid); UNUSED(pptinfo); return ResultFromScode(E_NOTIMPL); } /*** *HRESULT CPoly::GetIDsOfNames(OLECHAR**, unsigned int, LCID, long*) *Purpose: * This method translates the given array of names to a corresponding * array of DISPIDs. * * This method deferrs to a common implementation shared by * both the CPoly and CPoint objects. See the description of * 'SPolyGetIDsOfNames()' in dispimpl.cpp for more information. * *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 * rgdispid = array of DISPIDs corresponding to the rgszNames array * this array will contain -1 for each entry that is not known. * ***********************************************************************/ STDMETHODIMP CPoly::GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) { static PARAMDESC rgpdAddPoint[] = { {OLESTR("X")}, {OLESTR("Y")} }; static MEMBERDESC rgmdCPoly[] = { {OLESTR("DRAW"), IDMEMBER_CPOLY_DRAW, NULL, 0}, {OLESTR("RESET"), IDMEMBER_CPOLY_RESET, NULL, 0}, {OLESTR("ADDPOINT"), IDMEMBER_CPOLY_ADDPOINT, rgpdAddPoint, 2}, {OLESTR("ENUMPOINTS"), IDMEMBER_CPOLY_ENUMPOINTS, NULL, 0}, {OLESTR("GETXORIGIN"), IDMEMBER_CPOLY_GETXORIGIN, NULL, 0}, {OLESTR("SETXORIGIN"), IDMEMBER_CPOLY_SETXORIGIN, NULL, 0}, {OLESTR("GETYORIGIN"), IDMEMBER_CPOLY_GETYORIGIN, NULL, 0}, {OLESTR("SETYORIGIN"), IDMEMBER_CPOLY_SETYORIGIN, NULL, 0}, {OLESTR("GETWIDTH"), IDMEMBER_CPOLY_GETWIDTH, NULL, 0}, {OLESTR("SETWIDTH"), IDMEMBER_CPOLY_SETWIDTH, NULL, 0}, {OLESTR("get_red"), IDMEMBER_CPOLY_GETRED, NULL, 0}, {OLESTR("set_red"), IDMEMBER_CPOLY_SETRED, NULL, 0}, {OLESTR("get_green"), IDMEMBER_CPOLY_GETGREEN, NULL, 0}, {OLESTR("set_green"), IDMEMBER_CPOLY_SETGREEN, NULL, 0}, {OLESTR("get_blue"), IDMEMBER_CPOLY_GETBLUE, NULL, 0}, {OLESTR("set_blue"), IDMEMBER_CPOLY_SETBLUE, NULL, 0}, {OLESTR("DUMP"), IDMEMBER_CPOLY_DUMP, NULL, 0} }; // this object only exposes a "default" interface. // if(!IsEqualIID(riid, IID_NULL)) return ResultFromScode(DISP_E_UNKNOWNINTERFACE); return SPolyGetIDsOfNames( rgmdCPoly, DIM(rgmdCPoly), rgszNames, cNames, lcid, rgdispid); } /*** *HRESULT CPoly::Invoke(...) *Purpose: * Dispatch a method or property request for objects of type CPoly. * * 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 CPoly::Invoke( DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, unsigned int FAR* puArgErr) { HRESULT hresult; VARIANTARG varg0, varg1; VARIANT varResultDummy; UNUSED(lcid); UNUSED(pexcepinfo); if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) return ResultFromScode(E_INVALIDARG); // this object only exposes a "default" interface. // if(!IsEqualIID(riid, IID_NULL)) return ResultFromScode(DISP_E_UNKNOWNINTERFACE); // This makes the following code a bit simpler if the caller // happens to be ignoring the return value. Some implementations // may choose to deal with this differently. // if(pvarResult == (VARIANT FAR*)NULL) pvarResult = &varResultDummy; VariantInit(&varg0); VariantInit(&varg1); // assume the return type is void, unless we find otherwise. VariantInit(pvarResult); switch(dispidMember){ case IDMEMBER_CPOLY_DRAW: Draw(); break; case IDMEMBER_CPOLY_RESET: Reset(); break; case IDMEMBER_CPOLY_DUMP: Dump(); break; case IDMEMBER_CPOLY_ADDPOINT: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; hresult = DispGetParam(pdispparams, 1, VT_I2, &varg1, puArgErr); if(hresult != NOERROR) return hresult; hresult = AddPoint(V_I2(&varg1), V_I2(&varg0)); if(hresult != NOERROR) return hresult; break; case IDMEMBER_CPOLY_ENUMPOINTS: IEnumVARIANT FAR* penum; hresult = EnumPoints(&penum); if(hresult != NOERROR) return hresult; V_VT(pvarResult) = VT_UNKNOWN; hresult = penum->QueryInterface( IID_IUnknown, (void FAR* FAR*)&V_UNKNOWN(pvarResult)); if(hresult != NOERROR) return hresult; penum->Release(); break; case IDMEMBER_CPOLY_GETXORIGIN: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = m_xorg; break; case IDMEMBER_CPOLY_SETXORIGIN: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; m_xorg = V_I2(&varg0); break; case IDMEMBER_CPOLY_GETYORIGIN: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = m_yorg; break; case IDMEMBER_CPOLY_SETYORIGIN: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; m_yorg = V_I2(&varg0); break; case IDMEMBER_CPOLY_GETWIDTH: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = GetWidth(); break; case IDMEMBER_CPOLY_SETWIDTH: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; SetWidth(V_I2(&varg0)); break; case IDMEMBER_CPOLY_GETRED: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = get_red(); break; case IDMEMBER_CPOLY_SETRED: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; set_red(V_I2(&varg0)); break; case IDMEMBER_CPOLY_GETGREEN: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = get_green(); break; case IDMEMBER_CPOLY_SETGREEN: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; set_green(V_I2(&varg0)); break; case IDMEMBER_CPOLY_GETBLUE: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = get_blue(); break; case IDMEMBER_CPOLY_SETBLUE: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; set_blue(V_I2(&varg0)); break; default: return ResultFromScode(DISP_E_MEMBERNOTFOUND); } return NOERROR; } //--------------------------------------------------------------------- // Introduced Methods //--------------------------------------------------------------------- /*** *void CPoly::Draw(void) *Purpose: * Draw the polygon, using the current x/y origin and line width * properties. * *Entry: * None * *Exit: * None * ***********************************************************************/ void PASCAL CPoly::Draw() { short xorg, yorg; POINTLINK FAR* ppointlinkFirst, FAR* ppointlink; if((ppointlinkFirst = m_ppointlink) == (POINTLINK FAR*)NULL) return; #ifdef _MAC /* { */ short x, y; RGBColor rgb; WindowPtr pwndSaved; GetPort(&pwndSaved); SetPort(g_pwndClient); PenNormal(); PenSize(m_width, m_width); rgb.red = m_red; rgb.green = m_green; rgb.blue = m_blue; RGBForeColor(&rgb); xorg = m_xorg; yorg = m_yorg; MoveTo( xorg + ppointlinkFirst->ppoint->m_x, yorg + ppointlinkFirst->ppoint->m_y); for(ppointlink = ppointlinkFirst->next; ppointlink != (POINTLINK FAR*)NULL; ppointlink = ppointlink->next) { x = xorg + ppointlink->ppoint->m_x; y = yorg + ppointlink->ppoint->m_y; LineTo(x, y); } LineTo( xorg + ppointlinkFirst->ppoint->m_x, yorg + ppointlinkFirst->ppoint->m_y); SetPort(pwndSaved); #else /* }{ */ HDC hdc; RECT rect; HPEN hpen, hpenOld; extern HWND g_hwndClient; GetClientRect(g_hwndClient, &rect); xorg = m_xorg + (short) rect.left; yorg = m_yorg + (short) rect.top; hdc = GetDC(g_hwndClient); hpen = CreatePen(PS_SOLID, m_width, RGB(m_red, m_green, m_blue)); hpenOld = (HPEN)SelectObject(hdc, hpen); #ifdef WIN32 MoveToEx(hdc, xorg + ppointlinkFirst->ppoint->m_x, yorg + ppointlinkFirst->ppoint->m_y, NULL); #else MoveTo(hdc, xorg + ppointlinkFirst->ppoint->m_x, yorg + ppointlinkFirst->ppoint->m_y); #endif for(ppointlink = ppointlinkFirst->next; ppointlink != (POINTLINK FAR*)NULL; ppointlink = ppointlink->next) { LineTo(hdc, xorg + ppointlink->ppoint->m_x, yorg + ppointlink->ppoint->m_y); } LineTo(hdc, xorg + ppointlinkFirst->ppoint->m_x, yorg + ppointlinkFirst->ppoint->m_y); SelectObject(hdc, hpenOld); DeleteObject(hpen); ReleaseDC(g_hwndClient, hdc); #endif /* } */ } /*** *void CPoly::Reset(void) *Purpose: * Release all points referenced by this poly. * *Entry: * None * *Exit: * None * ***********************************************************************/ void PASCAL CPoly::Reset() { POINTLINK FAR* ppointlink, FAR* ppointlinkNext; for(ppointlink = m_ppointlink; ppointlink != (POINTLINK FAR*)NULL; ppointlink = ppointlinkNext) { ppointlinkNext = ppointlink->next; ppointlink->ppoint->Release(); delete ppointlink; } m_cPoints = 0; m_ppointlink = NULL; m_ppointlinkLast = NULL; } /*** *HRESULT CPoly::AddPoint(short, short) *Purpose: * Add a CPoint with the given coordinates to the end of our current * list of points. * *Entry: * x,y = the x and y coordinates of the new point. * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT PASCAL CPoly::AddPoint(short x, short y) { CPoint FAR* ppoint; POINTLINK FAR* ppointlink; ppoint = CPoint::Create(); if(ppoint == (CPoint FAR*)NULL) return ResultFromScode(E_OUTOFMEMORY); ppoint->SetX(x); ppoint->SetY(y); ppointlink = new FAR POINTLINK; if(ppointlink == (POINTLINK FAR*)NULL){ delete ppoint; return ResultFromScode(E_OUTOFMEMORY); } ppointlink->ppoint = ppoint; ppointlink->next = (POINTLINK FAR*)NULL; if(m_ppointlinkLast == (POINTLINK FAR*)NULL){ m_ppointlink = m_ppointlinkLast = ppointlink; }else{ m_ppointlinkLast->next = ppointlink; m_ppointlinkLast = ppointlink; } ++m_cPoints; return NOERROR; } /*** *HRESULT CPoly::EnumPoints(IEnumVARIANT**); *Purpose: * Return and enumerator for the points in this polygon. * *Entry: * None * *Exit: * return value = HRESULT * * *ppenum = pointer to an IEnumVARIANT for the points in this polygon * ***********************************************************************/ HRESULT PASCAL CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum) { unsigned int i; VARIANT var; HRESULT hresult; SAFEARRAY FAR* psa; CEnumPoint FAR* penum; POINTLINK FAR* ppointlink; SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = m_cPoints; psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound); if(psa == NULL){ hresult = ResultFromScode(E_OUTOFMEMORY); goto LError0; } ppointlink = m_ppointlink; for(i = 0; i < m_cPoints; ++i){ long ix[1]; if(ppointlink == NULL){ // this indicates an internal consistency error. // (this test should probably be an assertion) hresult = ResultFromScode(E_FAIL); goto LError1; } V_VT(&var) = VT_DISPATCH; hresult = ppointlink->ppoint->QueryInterface( IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var)); if(hresult != NOERROR) goto LError1; ix[0] = i; SafeArrayPutElement(psa, ix, &var); ppointlink = ppointlink->next; } hresult = CEnumPoint::Create(psa, &penum); if(hresult != NOERROR) goto LError1; *ppenum = penum; return NOERROR; LError1:; // destroy the array if we were not successful creating the enumerator. SafeArrayDestroy(psa); LError0:; return hresult; } short PASCAL CPoly::GetXOrigin() { return m_xorg; } void PASCAL CPoly::SetXOrigin(short x) { m_xorg = x; } short PASCAL CPoly::GetYOrigin() { return m_yorg; } void PASCAL CPoly::SetYOrigin(short y) { m_yorg = y; } short PASCAL CPoly::GetWidth() { return m_width; } void PASCAL CPoly::SetWidth(short width) { m_width = width; } short PASCAL CPoly::get_red() { return m_red; } void PASCAL CPoly::set_red(short red) { m_red = red; } short PASCAL CPoly::get_green() { return m_green; } void PASCAL CPoly::set_green(short green) { m_green = green; } short PASCAL CPoly::get_blue() { return m_blue; } void PASCAL CPoly::set_blue(short blue) { m_blue = blue; } /*** *void CPoly::Dump(void) *Purpose: * Output a debug dump of this instance. * *Entry: * None * *Exit: * None * ***********************************************************************/ void PASCAL CPoly::Dump() { #ifdef _MAC // REVIEW: implement for the mac #else TCHAR buffer[80]; POINTLINK FAR* ppointlink; wsprintf(buffer, TSTR("CPoly(0x%x) =\n"), (int)this); OutputDebugString(buffer); wsprintf(buffer, TSTR(" xorg = %d, yorg = %d, width = %d, rgb = {%d,%d,%d}\n points = "), m_xorg, m_yorg, m_width, get_red(), get_green(), get_blue()); OutputDebugString(buffer); for(ppointlink = m_ppointlink; ppointlink != (POINTLINK FAR*)NULL; ppointlink = ppointlink->next) { wsprintf(buffer, TSTR("{%d,%d}"), ppointlink->ppoint->GetX(), ppointlink->ppoint->GetY()); OutputDebugString(buffer); wsprintf(buffer, TSTR(" ")); OutputDebugString(buffer); } wsprintf(buffer, TSTR("\n")); OutputDebugString(buffer); #endif } /*** *void CPoly::PolyDraw(void) *Purpose: * Draw all polygons. * *Entry: * None * *Exit: * None * ***********************************************************************/ void CPoly::PolyDraw() { POLYLINK FAR* polylink; for(polylink = g_ppolylink; polylink != (POLYLINK FAR*)NULL; polylink = polylink->next) { polylink->ppoly->Draw(); } } /*** *void PolyTerm(void) *Purpose: * Release all polygons. * *Entry: * None * *Exit: * None * ***********************************************************************/ void CPoly::PolyTerm() { POLYLINK FAR* ppolylink; POLYLINK FAR* ppolylinkNext; for(ppolylink = g_ppolylink; ppolylink != (POLYLINK FAR*)NULL; ppolylink = ppolylinkNext) { ppolylinkNext = ppolylink->next; ppolylink->ppoly->Release(); delete ppolylink; } g_ppolylink = NULL; } /*** *void PolyDump(void) *Purpose: * Invoke the debug Dump() method on all polygons were currently * holding on to. * *Entry: * None * *Exit: * None * ***********************************************************************/ void CPoly::PolyDump() { POLYLINK FAR* ppolylink; if(g_ppolylink == (POLYLINK FAR*)NULL){ #ifndef _MAC OutputDebugString(TSTR("\t(none)\n")); #endif return; } for(ppolylink = g_ppolylink; ppolylink != (POLYLINK FAR*)NULL; ppolylink = ppolylink->next) { ppolylink->ppoly->Dump(); } } //--------------------------------------------------------------------- // Implementation of the CPoly Class Factory //--------------------------------------------------------------------- CPolyCF::CPolyCF() { m_refs = 0; } IClassFactory FAR* CPolyCF::Create() { CPolyCF FAR* pCF; if((pCF = new FAR CPolyCF()) == NULL) return NULL; pCF->AddRef(); return pCF; } STDMETHODIMP CPolyCF::QueryInterface(REFIID riid, void FAR* FAR* ppv) { if(!IsEqualIID(riid, IID_IUnknown)){ if(!IsEqualIID(riid, IID_IClassFactory)){ *ppv = NULL; return ResultFromScode(E_NOINTERFACE); } } *ppv = this; ++m_refs; return NOERROR; } STDMETHODIMP_(unsigned long) CPolyCF::AddRef(void) { return ++m_refs; } STDMETHODIMP_(unsigned long) CPolyCF::Release(void) { if(--m_refs == 0){ delete this; return 0; } return m_refs; } STDMETHODIMP CPolyCF::CreateInstance( IUnknown FAR* punkOuter, REFIID iid, void FAR* FAR* ppv) { HRESULT hresult; CPoly FAR *ppoly; UNUSED(punkOuter); #ifdef _MAC if(GetZone() != ApplicZone()){ #ifndef _MSC_VER #ifndef ConstStr255Param #define ConstStr255Param StringPtr #endif #endif DebugStr((ConstStr255Param)"\pZones do not match"); } #endif if((ppoly = CPoly::Create()) == NULL){ *ppv = NULL; return ResultFromScode(E_OUTOFMEMORY); } hresult = ppoly->QueryInterface(iid, ppv); ppoly->Release(); return hresult; } STDMETHODIMP #ifdef _MAC CPolyCF::LockServer(unsigned long fLock) #else CPolyCF::LockServer(BOOL fLock) #endif { UNUSED(fLock); return NOERROR; }