/*** *crempoly.cpp * * Copyright (C) 1992, Microsoft Corporation. All Rights Reserved. * Information Contained Herein Is Proprietary and Confidential. * *Purpose: * This file contains the implementation of CRemPoly, the remote polygon * class. This class presents a standard C++ vtable interface to the * rest of the application, and hides the details of talking to the * actual remote CPoly class exposed by the SPoly server. Each of * the introduced methods is simply a cover for an IDispatch invocation * of the actual method on the remote object. * *Implementation Notes: * * NOTE: this is a derivative of crempoly.cpp from the sample dispdemo, * but has been modified to for use in our test apps. This is no longer * a legit sample because it contains references to private definitions * from src/dispatch. * *****************************************************************************/ #include "common.h" #include "crempoly.h" // method names on the CPoly class. // OLECHAR FAR* CRemPoly::m_rgszMethods[] = { OLESTR("draw"), OLESTR("dump"), OLESTR("reset"), OLESTR("addpoint"), OLESTR("enumpoints"), OLESTR("getxorigin"), OLESTR("setxorigin"), OLESTR("getyorigin"), OLESTR("setyorigin"), OLESTR("getwidth"), OLESTR("setwidth"), OLESTR("get_red"), OLESTR("set_red"), OLESTR("get_green"), OLESTR("set_green"), OLESTR("get_blue"), OLESTR("set_blue") }; CRemPoly::CRemPoly() { m_refs = 0; m_pdisp = (IDispatch FAR*)NULL; } // A useful pre-initialized DISPATCHPARAMS, used on all the methods that // take 0 arguments. // DISPPARAMS g_dispparamsNoArgs = {NULL, NULL, 0, 0}; /*** *HRESULT CRemPoly::Create(OLECHAR*, CRemPoly**) * *Purpose: * This function creates an instance of the CRemPoly class, connects * it to the IDispatch interface of the remote CPoly class, and learns * the DISPIDs for the members (that we know about) exposed by that * class. * *Entry: * clsid = The CLSID of the CPoly we are to create. (taking this as a * param is a bit weird, but allows us to connect to several remote * versions. * *Exit: * return value = HRESULT * * *pprempoly = pointer to the newly created CRemPoly, if successfyl. * ***********************************************************************/ HRESULT CRemPoly::Create(OLECHAR FAR* szProgID, CRemPoly FAR* FAR* pprempoly) { int i; HRESULT hresult; CRemPoly FAR* prempoly; prempoly = new FAR CRemPoly(); if(prempoly == (CRemPoly FAR*)NULL){ hresult = ResultFromScode(E_OUTOFMEMORY); goto LError; } prempoly->AddRef(); hresult = CreateObject(szProgID, &prempoly->m_pdisp); if(hresult != NOERROR) goto LFreeCRemPoly; // We learn *all* the member IDs up front. A more sophisticated // implementation might defer learning about the IDs for a given // method until the first time the method is invoked, thereby // amortizing the creation costs. // for(i = 0; i < IMETH_CREMPOLY_MAX; ++i){ hresult = prempoly->m_pdisp->GetIDsOfNames( IID_NULL, &prempoly->m_rgszMethods[i], 1, LOCALE_SYSTEM_DEFAULT, &prempoly->m_rgdispid[i]); if(hresult != NOERROR) goto LFreeCRemPoly; } *pprempoly = prempoly; return NOERROR; LFreeCRemPoly:; prempoly->Release(); LError:; return hresult; } //--------------------------------------------------------------------- // IUnknown methods //--------------------------------------------------------------------- /*** *HRESULT CRemPoly::QueryInterface(REFIID, void**) * *Purpose: * Standard Ole2 implementation of QueryInterface. This class * supports the IUnknown interface, and introduces a number of * nonvirtual members. * *Entry: * riid = reference to the requested interface id * *Exit: * return value = HRESULT * *ppv = pointer to the requested interface, if successful. * ***********************************************************************/ STDMETHODIMP CRemPoly::QueryInterface(REFIID riid, void FAR* FAR* ppv) { if(IsEqualIID(riid, IID_IUnknown)){ *ppv = this; AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); } /*** *unsigned long CRemPoly::AddRef(void) * *Purpose: * Add a reference to the instance. * *Entry: * None * *Exit: * return value = unsigned long. The resulting reference count. * ***********************************************************************/ STDMETHODIMP_(unsigned long) CRemPoly::AddRef(void) { return ++m_refs; } /*** *unsigned long CRemPoly::Release(void) * *Purpose: * Release a reference to the instance. If the reference count goes * to zero, delete the instance. * *Entry: * None * *Exit: * return value = unsigned long. The resulting reference count. * ***********************************************************************/ STDMETHODIMP_(unsigned long) CRemPoly::Release(void) { if(--m_refs == 0){ if(m_pdisp != (IDispatch FAR*)NULL){ m_pdisp->Release(); } delete this; return 0; } return m_refs; } //--------------------------------------------------------------------- // Introduced methods //--------------------------------------------------------------------- /* * Each of these methods is simply a cover for an IDispatch Invocation * of the actual method on the remote CPoly class. This allows CRemPoly * to present an interface that looks and acts just like the CPoly * object, even though the actual work is being done in another process. * */ /*** *HRESULT CRemPoly::Draw(void) * *Purpose: * Invoke the Draw method on the remote CPoly instance. * *Entry: * None * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::Draw() { return m_pdisp->Invoke( m_rgdispid[IMETH_CREMPOLY_DRAW], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &g_dispparamsNoArgs, NULL, NULL, NULL); } /*** *HRESULT CRemPoly::Dump(void) * *Purpose: * Invoke the Dump() method on the remote CPoly instance. This method * dumps the contained CPoints and writes the properties of the remote * CPoly instance to the debug window. * *Entry: * None * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::Dump() { return m_pdisp->Invoke( m_rgdispid[IMETH_CREMPOLY_DUMP], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &g_dispparamsNoArgs, NULL, NULL, NULL); } /*** *HRESULT CRemPoly::Reset(void) * *Purpose: * Invoke the Reset() method on the remote CPoly instance. The Reset() * method causes the remote CPoly to release all contained CPoints. * *Entry: * None * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::Reset() { return m_pdisp->Invoke( m_rgdispid[IMETH_CREMPOLY_RESET], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &g_dispparamsNoArgs, NULL, NULL, NULL); } /*** *HRESULT CRemPoly::AddPoint(short, short) * *Purpose: * Invoke the AddPoint method in the remote CPoly object to add a * new point with the given coordinates to this instance. * *Entry: * x,y = the x and y coordinates of the new point. * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::AddPoint(short x, short y) { HRESULT hresult; VARIANTARG rgvarg[2]; DISPPARAMS dispparams; V_VT(&rgvarg[0]) = VT_I2; V_I2(&rgvarg[0]) = y; V_VT(&rgvarg[1]) = VT_I2; V_I2(&rgvarg[1]) = x; dispparams.cArgs = 2; dispparams.rgvarg = rgvarg; dispparams.cNamedArgs = 0; dispparams.rgdispidNamedArgs = NULL; hresult = m_pdisp->Invoke( m_rgdispid[IMETH_CREMPOLY_ADDPOINT], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, NULL, NULL); return hresult; } /*** *HRESULT CRemPoly::EnumPoints(IEnumVARIANT**) *Purpose: * Inoke the EnumPoints() method in the remote object to * get a enumerator for the points contained in the current poly. * *Entry: * None * *Exit: * return value = HRESULT * * *ppenum = pointer to the point enumerator * ***********************************************************************/ HRESULT CRemPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum) { HRESULT hresult; IEnumVARIANT FAR* penum; VARIANT varResult, FAR* pvarResult; pvarResult = &varResult; VariantInit(pvarResult); hresult = m_pdisp->Invoke( m_rgdispid[IMETH_CREMPOLY_ENUMPOINTS], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &g_dispparamsNoArgs, pvarResult, NULL, NULL); if(hresult != NOERROR) return hresult; if(V_VT(pvarResult) != VT_UNKNOWN) return ResultFromScode(E_FAIL); hresult = V_UNKNOWN(pvarResult)->QueryInterface( IID_IEnumVARIANT, (void FAR* FAR*)&penum); if(hresult == NOERROR) *ppenum = penum; VariantClear(pvarResult); return NOERROR; } /*** *HRESULT CRemPoly::GetXOrigin(short*) * *Purpose: * Invoke the GetXOrigin() method on the remote object to extract * the current value of the XOrigin property. * *Entry: * None * *Exit: * return value = HRESULT * * *pxorg = the current X origin of the polygon. * ***********************************************************************/ HRESULT CRemPoly::GetXOrigin(short FAR* pxorg) { return get_i2(m_rgdispid[IMETH_CREMPOLY_GETXORIGIN], pxorg); } /*** *HRESULT CRemPoly::SetXOrigin(short) * *Purpose: * Invoke the SetXOrigin method on the remote object to set the * XOrigin property of the polygon to the given value. * *Entry: * xorg = the new X origin * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::SetXOrigin(short xorg) { return set_i2(m_rgdispid[IMETH_CREMPOLY_SETXORIGIN], xorg); } /*** *HRESULT CRemPoly::GetYOrigin(short*) * *Purpose: * Invoke the GetYOrigin() method on the remote object to extract * the current value of the YOrigin property. * *Entry: * None * *Exit: * return value = HRESULT * * *pyorg = the current Y origin of the polygon * ***********************************************************************/ HRESULT CRemPoly::GetYOrigin(short FAR* pyorg) { return get_i2(m_rgdispid[IMETH_CREMPOLY_GETYORIGIN], pyorg); } /*** *HRESULT CRemPoly::SetYOrigin(short) * *Purpose: * Invoke the SetYOrigin method on the remote object to set the * YOrigin property of the polygon to the given value. * *Entry: * yorg = the new Y origin * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::SetYOrigin(short yorg) { return set_i2(m_rgdispid[IMETH_CREMPOLY_SETYORIGIN], yorg); } /*** *HRESULT CRemPoly::GetWidth(short*) * *Purpose: * Invoke the GetWidth() method on the remote object to extract * the current value of the line width property. * *Entry: * None * *Exit: * return value = HRESULT * * *pwidth = short, the current line width of the polygon * ***********************************************************************/ HRESULT CRemPoly::GetWidth(short FAR* pwidth) { return get_i2(m_rgdispid[IMETH_CREMPOLY_GETWIDTH], pwidth); } /*** *HRESULT CRemPoly::SetWidth(short) * *Purpose: * Invoke the SetWidth method on the remote object to set the * line width property of the polygon to the given value. * *Entry: * width = the new value for the line width property. * *Exit: * return value = HRESULT * ***********************************************************************/ HRESULT CRemPoly::SetWidth(short width) { return set_i2(m_rgdispid[IMETH_CREMPOLY_SETWIDTH], width); } HRESULT CRemPoly::get_red(short FAR* psRed) { return get_i2(m_rgdispid[IMETH_CREMPOLY_GETRED], psRed); } HRESULT CRemPoly::set_red(short sRed) { return set_i2(m_rgdispid[IMETH_CREMPOLY_SETRED], sRed); } HRESULT CRemPoly::get_green(short FAR* psGreen) { return get_i2(m_rgdispid[IMETH_CREMPOLY_GETGREEN], psGreen); } HRESULT CRemPoly::set_green(short sGreen) { return set_i2(m_rgdispid[IMETH_CREMPOLY_SETGREEN], sGreen); } HRESULT CRemPoly::get_blue(short FAR* psBlue) { return get_i2(m_rgdispid[IMETH_CREMPOLY_GETBLUE], psBlue); } HRESULT CRemPoly::set_blue(short sBlue) { return set_i2(m_rgdispid[IMETH_CREMPOLY_SETBLUE], sBlue); } HRESULT CRemPoly::get_i2(DISPID dispid, short FAR* ps) { HRESULT hresult; VARIANT varResult; VariantInit(&varResult); hresult = m_pdisp->Invoke( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &g_dispparamsNoArgs, &varResult, NULL, NULL); if(hresult != NOERROR) return hresult; hresult = VariantChangeType(&varResult, &varResult, 0, VT_I2); if(hresult != NOERROR){ VariantClear(&varResult); return hresult; } *ps = V_I2(&varResult); return NOERROR; } HRESULT CRemPoly::set_i2(DISPID dispid, short s) { VARIANTARG varg; DISPPARAMS dispparams; V_VT(&varg) = VT_I2; V_I2(&varg) = s; dispparams.cArgs = 1; dispparams.cNamedArgs = 0; dispparams.rgvarg = &varg; return m_pdisp->Invoke( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, NULL, NULL); }