home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / oleaut / spoly / cpoly.cpp < prev    next >
C/C++ Source or Header  |  1997-08-01  |  24KB  |  1,075 lines

  1. /*** 
  2. *CPoly.cpp
  3. *
  4. *  This is a part of the Microsoft Source Code Samples.
  5. *
  6. *  Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
  7. *
  8. *  This source code is only intended as a supplement to Microsoft Development
  9. *  Tools and/or WinHelp documentation.  See these sources for detailed
  10. *  information regarding the Microsoft samples programs.
  11. *
  12. *Purpose:
  13. *  This module implements the CPoly and CPolyCF classes.
  14. *
  15. *  This module is intended as a sample implementation of the IDispatch
  16. *  interface, and its purpose is to demonstrate how an object can
  17. *  expose methods and properties for programatic and cross-process
  18. *  access via the IDispatch interface.
  19. *
  20. *Implementation Notes:
  21. *
  22. *****************************************************************************/
  23.  
  24. #include "spoly.h"
  25. #include "cpoint.h"
  26. #include "cpoly.h"
  27. #include "cenumpt.h"
  28.  
  29. #ifndef _MAC
  30. extern CStatBar FAR* g_psb;
  31. #else
  32. extern "C" WindowPtr g_pwndClient;
  33. #endif
  34.  
  35. extern unsigned int g_fQuit;
  36.  
  37. // our global list of polygons.
  38. //
  39. POLYLINK FAR* g_ppolylink = (POLYLINK FAR*)NULL;
  40.  
  41. // global count of polygons.
  42. //
  43. int g_cPoly = 0;
  44.  
  45.  
  46. CPoly::CPoly()
  47. {
  48.     m_refs = 0;
  49.     m_xorg = 0;
  50.     m_yorg = 0;
  51.     m_width = 0;
  52.     m_cPoints = 0;
  53.  
  54.     m_red   = 0;
  55.     m_green = 0;
  56.     m_blue  = 0;
  57.  
  58.     m_ppointlink = NULL;
  59.     m_ppointlinkLast = NULL;
  60. }
  61.  
  62.  
  63. /***
  64. *CPoly *CPoly::Create(void)
  65. *Purpose:
  66. *  Create an instance of a CPoly object, and add it to the global
  67. *  list of polygons.
  68. *
  69. *Entry:
  70. *  None
  71. *
  72. *Exit:
  73. *  returns a polygon object, NULL the allocation failed.
  74. *
  75. ***********************************************************************/
  76. CPoly FAR*
  77. CPoly::Create()
  78. {
  79.     CPoly FAR* ppoly;
  80.     POLYLINK FAR* ppolylink;
  81.  
  82.     if((ppolylink = new FAR POLYLINK) == (POLYLINK FAR*)NULL)
  83.       return (CPoly FAR*)NULL;
  84.  
  85.     if((ppoly = new FAR CPoly()) == (CPoly FAR*)NULL)
  86.       return (CPoly FAR*)NULL;
  87.  
  88.     ppoly->AddRef();
  89.  
  90.     // push the new polygon onto the front of the polygon list.
  91.     //
  92.     ++g_cPoly;
  93.  
  94.     ppolylink->ppoly = ppoly;
  95.  
  96.     ppolylink->next = g_ppolylink;
  97.     g_ppolylink = ppolylink;
  98.  
  99. #ifndef _MAC
  100.     SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly);
  101. #endif
  102.  
  103.     IncObjectCount();
  104.  
  105.     return ppoly;
  106. }
  107.  
  108.  
  109. //---------------------------------------------------------------------
  110. //                     IUnknown Methods
  111. //---------------------------------------------------------------------
  112.  
  113.  
  114. STDMETHODIMP
  115. CPoly::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  116. {
  117.     if(IsEqualIID(riid, IID_IUnknown) ||
  118.        IsEqualIID(riid, IID_IDispatch)) {
  119.       *ppv = this;
  120.       AddRef();
  121.       return NOERROR;       
  122.     }
  123.            
  124.     *ppv = NULL;
  125.     return E_NOINTERFACE;
  126. }
  127.  
  128.  
  129. STDMETHODIMP_(unsigned long)
  130. CPoly::AddRef()
  131. {
  132.     return ++m_refs;
  133. }
  134.  
  135.  
  136. STDMETHODIMP_(unsigned long)
  137. CPoly::Release()
  138. {
  139.     POLYLINK FAR* FAR* pppolylink, FAR* ppolylinkDead;
  140.  
  141.     if(--m_refs == 0){
  142.       Reset(); // release all CPoints
  143.  
  144.       // remove ourselves from the global list of polygons
  145.       //
  146.       for( pppolylink = &g_ppolylink;
  147.           *pppolylink != NULL;
  148.        pppolylink = &(*pppolylink)->next)
  149.       {
  150.     if((*pppolylink)->ppoly == this){
  151.       ppolylinkDead = *pppolylink;
  152.       *pppolylink = (*pppolylink)->next;
  153.       delete ppolylinkDead;
  154.       break;
  155.     }
  156.       }
  157.  
  158.       --g_cPoly;
  159.  
  160. #ifndef _MAC
  161.       SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly);
  162. #endif
  163.  
  164.       delete this;
  165.  
  166.       DecObjectCount();
  167.  
  168.       return 0;
  169.     }
  170.     return m_refs;
  171. }
  172.  
  173.  
  174. //---------------------------------------------------------------------
  175. //                     IDispatch Methods
  176. //---------------------------------------------------------------------
  177.  
  178.  
  179. /*
  180.  * NOTE: Support for the following two methods is not available
  181.  * in this version.
  182.  *
  183.  */
  184.  
  185. STDMETHODIMP
  186. CPoly::GetTypeInfoCount(unsigned int FAR* pctinfo)
  187. {
  188.     *pctinfo = 0;
  189.     return NOERROR;
  190. }
  191.  
  192.  
  193. STDMETHODIMP
  194. CPoly::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  195. {
  196.     UNUSED(itinfo);
  197.     UNUSED(lcid);
  198.     UNUSED(pptinfo);
  199.  
  200.     return E_NOTIMPL;
  201. }
  202.  
  203.  
  204. /***
  205. *HRESULT CPoly::GetIDsOfNames(OLECHAR**, unsigned int, LCID, long*)
  206. *Purpose:
  207. *  This method translates the given array of names to a corresponding
  208. *  array of DISPIDs.
  209. *
  210. *  This method deferrs to a common implementation shared by
  211. *  both the CPoly and CPoint objects. See the description of
  212. *  'SPolyGetIDsOfNames()' in dispimpl.cpp for more information.
  213. *
  214. *Entry:
  215. *  rgszNames = pointer to an array of names
  216. *  cNames = the number of names in the rgszNames array
  217. *  lcid = the callers locale ID
  218. *
  219. *Exit:
  220. *  return value = HRESULT
  221. *  rgdispid = array of DISPIDs corresponding to the rgszNames array
  222. *    this array will contain -1 for each entry that is not known.
  223. *
  224. ***********************************************************************/
  225. STDMETHODIMP
  226. CPoly::GetIDsOfNames(
  227.     REFIID riid,
  228.     OLECHAR FAR* FAR* rgszNames,
  229.     unsigned int cNames,
  230.     LCID lcid,
  231.     DISPID FAR* rgdispid)
  232. {
  233. static PARAM_DESC rgpdAddPoint[] = {
  234.     {OLESTR("X")}, {OLESTR("Y")}
  235. };
  236. static MEMBERDESC rgmdCPoly[] = {
  237.     {OLESTR("DRAW"),       IDMEMBER_CPOLY_DRAW,        NULL,        0},
  238.     {OLESTR("RESET"),       IDMEMBER_CPOLY_RESET,    NULL,        0},
  239.     {OLESTR("ADDPOINT"),   IDMEMBER_CPOLY_ADDPOINT,    rgpdAddPoint,    2},
  240.     {OLESTR("ENUMPOINTS"), IDMEMBER_CPOLY_ENUMPOINTS,    NULL,        0},
  241.     {OLESTR("GETXORIGIN"), IDMEMBER_CPOLY_GETXORIGIN,    NULL,        0},
  242.     {OLESTR("SETXORIGIN"), IDMEMBER_CPOLY_SETXORIGIN,    NULL,        0},
  243.     {OLESTR("GETYORIGIN"), IDMEMBER_CPOLY_GETYORIGIN,    NULL,        0},
  244.     {OLESTR("SETYORIGIN"), IDMEMBER_CPOLY_SETYORIGIN,    NULL,        0},
  245.     {OLESTR("GETWIDTH"),   IDMEMBER_CPOLY_GETWIDTH,    NULL,        0},
  246.     {OLESTR("SETWIDTH"),   IDMEMBER_CPOLY_SETWIDTH,    NULL,        0},
  247.     {OLESTR("get_red"),       IDMEMBER_CPOLY_GETRED,    NULL,        0},
  248.     {OLESTR("set_red"),       IDMEMBER_CPOLY_SETRED,    NULL,        0},
  249.     {OLESTR("get_green"),  IDMEMBER_CPOLY_GETGREEN,    NULL,        0},
  250.     {OLESTR("set_green"),  IDMEMBER_CPOLY_SETGREEN,    NULL,        0},
  251.     {OLESTR("get_blue"),   IDMEMBER_CPOLY_GETBLUE,    NULL,        0},
  252.     {OLESTR("set_blue"),   IDMEMBER_CPOLY_SETBLUE,    NULL,        0},
  253.     {OLESTR("DUMP"),       IDMEMBER_CPOLY_DUMP,        NULL,        0},
  254.     {OLESTR("Quit"),       IDMEMBER_CPOLY_QUIT,     NULL,       0}
  255. };
  256.  
  257.     // this object only exposes a "default" interface.
  258.     //
  259.     if(!IsEqualIID(riid, IID_NULL))
  260.       return DISP_E_UNKNOWNINTERFACE;
  261.  
  262.     return SPolyGetIDsOfNames(
  263.       rgmdCPoly, DIM(rgmdCPoly), rgszNames, cNames, lcid, rgdispid);
  264. }
  265.  
  266.  
  267. /***
  268. *HRESULT CPoly::Invoke(...)
  269. *Purpose:
  270. *  Dispatch a method or property request for objects of type CPoly.
  271. *
  272. *  see the IDispatch document for more information, and a general
  273. *  description of this method.
  274. *
  275. *Entry:
  276. *  dispidMember = the DISPID of the member being requested
  277. *
  278. *  riid = reference to the interface ID of the interface on this object
  279. *    that the requested member belongs to. IID_NULL means to interpret
  280. *    the member as belonging to the implementation defined "default"
  281. *    or "primary" interface.
  282. *
  283. *  lcid = the caller's locale ID
  284. *
  285. *  wFlags = flags indicating the type of access being requested
  286. *
  287. *  pdispparams = pointer to the DISPPARAMS struct containing the
  288. *    requested members arguments (if any) and its named parameter
  289. *    DISPIDs (if any).
  290. *
  291. *Exit:
  292. *  return value = HRESULT
  293. *   see the IDispatch spec for a description of possible success codes.
  294. *
  295. *  pvarResult = pointer to a caller allocated VARIANT containing
  296. *    the members return value (if any).
  297. *
  298. *  pexcepinfo = caller allocated exception info structure, this will
  299. *    be filled in only if an exception was raised that must be passed
  300. *    up through Invoke to an enclosing handler.
  301. *
  302. *  puArgErr = pointer to a caller allocated UINT, that will contain the
  303. *    index of the offending argument if a DISP_E_TYPEMISMATCH error
  304. *    was returned indicating that one of the arguments was of an
  305. *    incorrect type and/or could not be reasonably coerced to a proper
  306. *    type.
  307. *
  308. ***********************************************************************/
  309. STDMETHODIMP
  310. CPoly::Invoke(
  311.     DISPID dispidMember,
  312.     REFIID riid,
  313.     LCID lcid,
  314.     unsigned short wFlags,
  315.     DISPPARAMS FAR* pdispparams,
  316.     VARIANT FAR* pvarResult,
  317.     EXCEPINFO FAR* pexcepinfo,
  318.     unsigned int FAR* puArgErr)
  319. {
  320.     HRESULT hresult;
  321.     VARIANTARG varg0, varg1;
  322.     VARIANT varResultDummy;
  323.  
  324.     UNUSED(lcid);
  325.     UNUSED(pexcepinfo);
  326.  
  327.     if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
  328.       return E_INVALIDARG;
  329.  
  330.     // this object only exposes a "default" interface.
  331.     //
  332.     if(!IsEqualIID(riid, IID_NULL))
  333.       return DISP_E_UNKNOWNINTERFACE;
  334.  
  335.     // This makes the following code a bit simpler if the caller
  336.     // happens to be ignoring the return value. Some implementations
  337.     // may choose to deal with this differently.
  338.     //
  339.     if(pvarResult == (VARIANT FAR*)NULL)
  340.       pvarResult = &varResultDummy;
  341.  
  342.     VariantInit(&varg0);
  343.     VariantInit(&varg1);
  344.  
  345.     // assume the return type is void, unless we find otherwise.
  346.     VariantInit(pvarResult);
  347.  
  348.     switch(dispidMember){
  349.     case IDMEMBER_CPOLY_DRAW:
  350.       Draw();
  351.       break;
  352.  
  353.     case IDMEMBER_CPOLY_RESET:
  354.       Reset();
  355.       break;
  356.  
  357.     case IDMEMBER_CPOLY_DUMP:
  358.       Dump();
  359.       break;
  360.  
  361.     case IDMEMBER_CPOLY_QUIT:
  362.       Quit();
  363.       break;
  364.  
  365.     case IDMEMBER_CPOLY_ADDPOINT:
  366.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  367.       if(hresult != NOERROR)
  368.     return hresult;
  369.  
  370.       hresult = DispGetParam(pdispparams, 1, VT_I2, &varg1, puArgErr);
  371.       if(hresult != NOERROR)
  372.     return hresult;
  373.  
  374.       hresult = AddPoint(V_I2(&varg1), V_I2(&varg0));
  375.       if(hresult != NOERROR)
  376.     return hresult;
  377.       break;
  378.  
  379.     case IDMEMBER_CPOLY_ENUMPOINTS:
  380.       IEnumVARIANT FAR* penum;
  381.  
  382.       hresult = EnumPoints(&penum);
  383.       if(hresult != NOERROR)
  384.     return hresult;
  385.  
  386.       V_VT(pvarResult) = VT_UNKNOWN;
  387.       hresult = penum->QueryInterface(
  388.     IID_IUnknown, (void FAR* FAR*)&V_UNKNOWN(pvarResult));
  389.       if(hresult != NOERROR)
  390.     return hresult;
  391.       penum->Release();
  392.       break;
  393.  
  394.     case IDMEMBER_CPOLY_GETXORIGIN:
  395.       V_VT(pvarResult) = VT_I2;
  396.       V_I2(pvarResult) = m_xorg;
  397.       break;
  398.  
  399.     case IDMEMBER_CPOLY_SETXORIGIN:
  400.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  401.       if(hresult != NOERROR)
  402.         return hresult;
  403.       m_xorg = V_I2(&varg0);
  404.       break;
  405.  
  406.     case IDMEMBER_CPOLY_GETYORIGIN:
  407.       V_VT(pvarResult) = VT_I2;
  408.       V_I2(pvarResult) = m_yorg;
  409.       break;
  410.  
  411.     case IDMEMBER_CPOLY_SETYORIGIN:
  412.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  413.       if(hresult != NOERROR)
  414.         return hresult;
  415.       m_yorg = V_I2(&varg0);
  416.       break;
  417.  
  418.     case IDMEMBER_CPOLY_GETWIDTH:
  419.       V_VT(pvarResult) = VT_I2;
  420.       V_I2(pvarResult) = GetWidth();
  421.       break;
  422.  
  423.     case IDMEMBER_CPOLY_SETWIDTH:
  424.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  425.       if(hresult != NOERROR)
  426.         return hresult;
  427.       SetWidth(V_I2(&varg0));
  428.       break;
  429.  
  430.     case IDMEMBER_CPOLY_GETRED:
  431.       V_VT(pvarResult) = VT_I2;
  432.       V_I2(pvarResult) = get_red();
  433.       break;
  434.  
  435.     case IDMEMBER_CPOLY_SETRED:
  436.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  437.       if(hresult != NOERROR)
  438.         return hresult;
  439.       set_red(V_I2(&varg0));
  440.       break;
  441.  
  442.     case IDMEMBER_CPOLY_GETGREEN:
  443.       V_VT(pvarResult) = VT_I2;
  444.       V_I2(pvarResult) = get_green();
  445.       break;
  446.  
  447.     case IDMEMBER_CPOLY_SETGREEN:
  448.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  449.       if(hresult != NOERROR)
  450.         return hresult;
  451.       set_green(V_I2(&varg0));
  452.       break;
  453.  
  454.     case IDMEMBER_CPOLY_GETBLUE:
  455.       V_VT(pvarResult) = VT_I2;
  456.       V_I2(pvarResult) = get_blue();
  457.       break;
  458.  
  459.     case IDMEMBER_CPOLY_SETBLUE:
  460.       hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
  461.       if(hresult != NOERROR)
  462.         return hresult;
  463.       set_blue(V_I2(&varg0));
  464.       break;
  465.  
  466.     default:
  467.       return DISP_E_MEMBERNOTFOUND;
  468.     }
  469.  
  470.     return NOERROR;
  471. }
  472.  
  473.  
  474. //---------------------------------------------------------------------
  475. //                     Introduced Methods
  476. //---------------------------------------------------------------------
  477.  
  478.  
  479. /***
  480. *void CPoly::Draw(void)
  481. *Purpose:
  482. *  Draw the polygon, using the current x/y origin and line width
  483. *  properties.
  484. *
  485. *Entry:
  486. *  None
  487. *
  488. *Exit:
  489. *  None
  490. *
  491. ***********************************************************************/
  492. void PASCAL
  493. CPoly::Draw()
  494. {
  495.     short xorg, yorg;
  496.     POINTLINK FAR* ppointlinkFirst, FAR* ppointlink;
  497.  
  498.     if((ppointlinkFirst = m_ppointlink) == (POINTLINK FAR*)NULL)
  499.       return;
  500.  
  501. #ifdef _MAC /* { */
  502.  
  503.     short x, y;
  504.     RGBColor rgb;
  505.     WindowPtr pwndSaved;
  506.  
  507.     GetPort(&pwndSaved);
  508.     SetPort(g_pwndClient);
  509.  
  510.     PenNormal();
  511.     PenSize(m_width, m_width);
  512.  
  513.     rgb.red = m_red;
  514.     rgb.green = m_green;
  515.     rgb.blue = m_blue;
  516.     RGBForeColor(&rgb);
  517.  
  518.     xorg = m_xorg;
  519.     yorg = m_yorg;
  520.  
  521.     MoveTo(
  522.       xorg + ppointlinkFirst->ppoint->m_x,
  523.       yorg + ppointlinkFirst->ppoint->m_y);
  524.  
  525.     for(ppointlink = ppointlinkFirst->next;
  526.     ppointlink != (POINTLINK FAR*)NULL;
  527.     ppointlink = ppointlink->next)
  528.     {
  529.       x = xorg + ppointlink->ppoint->m_x;
  530.       y = yorg + ppointlink->ppoint->m_y;
  531.       LineTo(x, y);
  532.     }
  533.  
  534.     LineTo(
  535.       xorg + ppointlinkFirst->ppoint->m_x,
  536.       yorg + ppointlinkFirst->ppoint->m_y);
  537.  
  538.     SetPort(pwndSaved);
  539.  
  540. #else /* }{ */
  541.  
  542.     HDC hdc;
  543.     RECT rect;
  544.     HPEN hpen, hpenOld;
  545. extern HWND g_hwndClient;
  546.  
  547.     GetClientRect(g_hwndClient, &rect);
  548.     xorg = m_xorg + (short) rect.left;
  549.     yorg = m_yorg + (short) rect.top;
  550.  
  551.     hdc = GetDC(g_hwndClient);
  552.     hpen = CreatePen(PS_SOLID, m_width, RGB(m_red, m_green, m_blue));
  553.     hpenOld = (HPEN)SelectObject(hdc, hpen);
  554.     
  555. #ifdef WIN32
  556.     MoveToEx(hdc,
  557.       xorg + ppointlinkFirst->ppoint->m_x,
  558.       yorg + ppointlinkFirst->ppoint->m_y, NULL);
  559. #else
  560.     MoveTo(hdc,
  561.       xorg + ppointlinkFirst->ppoint->m_x,
  562.       yorg + ppointlinkFirst->ppoint->m_y);
  563. #endif
  564.  
  565.     for(ppointlink = ppointlinkFirst->next;
  566.     ppointlink != (POINTLINK FAR*)NULL;
  567.     ppointlink = ppointlink->next)
  568.     {
  569.       LineTo(hdc,
  570.     xorg + ppointlink->ppoint->m_x,
  571.     yorg + ppointlink->ppoint->m_y);
  572.     }
  573.  
  574.     LineTo(hdc,
  575.       xorg + ppointlinkFirst->ppoint->m_x,
  576.       yorg + ppointlinkFirst->ppoint->m_y);
  577.  
  578.     SelectObject(hdc, hpenOld);
  579.     DeleteObject(hpen);
  580.  
  581.     ReleaseDC(g_hwndClient, hdc);
  582.  
  583. #endif /* } */
  584. }
  585.  
  586.  
  587. /***
  588. *void CPoly::Reset(void)
  589. *Purpose:
  590. *  Release all points referenced by this poly.
  591. *
  592. *Entry:
  593. *  None
  594. *
  595. *Exit:
  596. *  None
  597. *
  598. ***********************************************************************/
  599. void PASCAL
  600. CPoly::Reset()
  601. {
  602.     POINTLINK FAR* ppointlink, FAR* ppointlinkNext;
  603.  
  604.     for(ppointlink = m_ppointlink;
  605.     ppointlink != (POINTLINK FAR*)NULL;
  606.     ppointlink = ppointlinkNext)
  607.     {
  608.       ppointlinkNext = ppointlink->next;
  609.       ppointlink->ppoint->Release();
  610.       delete ppointlink;
  611.     }
  612.  
  613.     m_cPoints = 0;
  614.     m_ppointlink = NULL;
  615.     m_ppointlinkLast = NULL;
  616. }
  617.  
  618.  
  619. /***
  620. *HRESULT CPoly::AddPoint(short, short)
  621. *Purpose:
  622. *  Add a CPoint with the given coordinates to the end of our current
  623. *  list of points.
  624. *
  625. *Entry:
  626. *  x,y = the x and y coordinates of the new point.
  627. *
  628. *Exit:
  629. *  return value = HRESULT
  630. *
  631. ***********************************************************************/
  632. HRESULT PASCAL
  633. CPoly::AddPoint(short x, short y)
  634. {
  635.     CPoint FAR* ppoint;
  636.     POINTLINK FAR* ppointlink;
  637.  
  638.     ppoint = CPoint::Create();
  639.     if(ppoint == (CPoint FAR*)NULL)
  640.       return E_OUTOFMEMORY;
  641.  
  642.     ppoint->SetX(x);
  643.     ppoint->SetY(y);
  644.  
  645.     ppointlink = new FAR POINTLINK;
  646.     if(ppointlink == (POINTLINK FAR*)NULL){
  647.       delete ppoint;
  648.       return E_OUTOFMEMORY;
  649.     }
  650.  
  651.     ppointlink->ppoint = ppoint;
  652.     ppointlink->next = (POINTLINK FAR*)NULL;
  653.  
  654.     if(m_ppointlinkLast == (POINTLINK FAR*)NULL){
  655.       m_ppointlink = m_ppointlinkLast = ppointlink;
  656.     }else{
  657.       m_ppointlinkLast->next = ppointlink;
  658.       m_ppointlinkLast = ppointlink;
  659.     }
  660.  
  661.     ++m_cPoints;
  662.  
  663.     return NOERROR;
  664. }
  665.  
  666.  
  667. /***
  668. *HRESULT CPoly::EnumPoints(IEnumVARIANT**);
  669. *Purpose:
  670. *  Return and enumerator for the points in this polygon.
  671. *
  672. *Entry:
  673. *  None
  674. *
  675. *Exit:
  676. *  return value = HRESULT
  677. *
  678. *  *ppenum = pointer to an IEnumVARIANT for the points in this polygon
  679. *
  680. ***********************************************************************/
  681. HRESULT PASCAL
  682. CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)
  683. {
  684.     unsigned int i;
  685.     VARIANT var;
  686.     HRESULT hresult;
  687.     SAFEARRAY FAR* psa;
  688.     CEnumPoint FAR* penum;
  689.     POINTLINK FAR* ppointlink;
  690.     SAFEARRAYBOUND rgsabound[1];
  691.  
  692.     rgsabound[0].lLbound = 0;
  693.     rgsabound[0].cElements = m_cPoints;
  694.  
  695.     psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
  696.     if(psa == NULL){
  697.       hresult = E_OUTOFMEMORY;
  698.       goto LError0;
  699.     }
  700.  
  701.     ppointlink = m_ppointlink;
  702.     for(i = 0; i < m_cPoints; ++i){
  703.       long ix[1];
  704.  
  705.       if(ppointlink == NULL){
  706.         // this indicates an internal consistency error.
  707.     // (this test should probably be an assertion)
  708.         hresult = E_FAIL;
  709.         goto LError1;
  710.       }
  711.  
  712.       V_VT(&var) = VT_DISPATCH;
  713.       hresult = ppointlink->ppoint->QueryInterface(
  714.     IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var));
  715.       if(hresult != NOERROR)
  716.         goto LError1;
  717.  
  718.       ix[0] = i;
  719.       SafeArrayPutElement(psa, ix, &var);
  720.  
  721.       // SafeArrayPutElement adds a reference to the contents of the
  722.       // variant, so we must free the variable we have.
  723.       //
  724.       VariantClear(&var);
  725.  
  726.       ppointlink = ppointlink->next;
  727.     }
  728.  
  729.     hresult = CEnumPoint::Create(psa, &penum);
  730.     if(hresult != NOERROR)
  731.       goto LError1;
  732.  
  733.     *ppenum = penum;
  734.  
  735.     return NOERROR;
  736.  
  737. LError1:;
  738.     // destroy the array if we were not successful creating the enumerator.
  739.     SafeArrayDestroy(psa);
  740.  
  741. LError0:;
  742.     return hresult;
  743. }
  744.  
  745. short PASCAL
  746. CPoly::GetXOrigin()
  747. {
  748.     return m_xorg;
  749. }
  750.  
  751. void PASCAL
  752. CPoly::SetXOrigin(short x)
  753. {
  754.     m_xorg = x;
  755. }
  756.  
  757. short PASCAL
  758. CPoly::GetYOrigin()
  759. {
  760.     return m_yorg;
  761. }
  762.  
  763. void PASCAL
  764. CPoly::SetYOrigin(short y)
  765. {
  766.     m_yorg = y;
  767. }
  768.  
  769. short PASCAL
  770. CPoly::GetWidth()
  771. {
  772.     return m_width;
  773. }
  774.  
  775. void PASCAL
  776. CPoly::SetWidth(short width)
  777. {
  778.     m_width = width;
  779. }
  780.  
  781. short PASCAL
  782. CPoly::get_red()
  783. {
  784.     return m_red;
  785. }
  786.  
  787. void PASCAL
  788. CPoly::set_red(short red)
  789. {
  790.     m_red = red;
  791. }
  792.  
  793. short PASCAL
  794. CPoly::get_green()
  795. {
  796.     return m_green;
  797. }
  798.  
  799. void PASCAL
  800. CPoly::set_green(short green)
  801. {
  802.     m_green = green;
  803. }
  804.  
  805. short PASCAL
  806. CPoly::get_blue()
  807. {
  808.     return m_blue;
  809. }
  810.  
  811. void PASCAL
  812. CPoly::set_blue(short blue)
  813. {
  814.     m_blue = blue;
  815. }
  816.  
  817.  
  818. /***
  819. *void CPoly::Dump(void)
  820. *Purpose:
  821. *  Output a debug dump of this instance.
  822. *
  823. *Entry:
  824. *  None
  825. *
  826. *Exit:
  827. *  None
  828. *
  829. ***********************************************************************/
  830. void PASCAL
  831. CPoly::Dump()
  832. {
  833. #ifdef _MAC
  834.  
  835.     // REVIEW: implement for the mac
  836.  
  837. #else
  838.  
  839.     TCHAR buffer[80];
  840.     POINTLINK FAR* ppointlink;
  841.  
  842.     wsprintf(buffer, TSTR("CPoly(0x%x) =\n"), (int)this);
  843.     OutputDebugString(buffer);
  844.  
  845.     wsprintf(buffer,
  846.       TSTR("    xorg = %d, yorg = %d, width = %d, rgb = {%d,%d,%d}\n    points = "),
  847.       m_xorg, m_yorg, m_width,
  848.       get_red(),
  849.       get_green(),
  850.       get_blue());
  851.  
  852.     OutputDebugString(buffer);
  853.  
  854.     for(ppointlink = m_ppointlink;
  855.     ppointlink != (POINTLINK FAR*)NULL;
  856.     ppointlink = ppointlink->next)
  857.     {
  858.       wsprintf(buffer, TSTR("{%d,%d}"),
  859.         ppointlink->ppoint->GetX(),
  860.         ppointlink->ppoint->GetY());
  861.       OutputDebugString(buffer);
  862.  
  863.       wsprintf(buffer, TSTR(" "));
  864.       OutputDebugString(buffer);
  865.     }
  866.     wsprintf(buffer, TSTR("\n"));
  867.     OutputDebugString(buffer);
  868.  
  869. #endif
  870. }
  871.  
  872. /***
  873. *void CPoly::Quit(void)
  874. *Purpose:
  875. *  Exit when all objects are released.
  876. *
  877. *Entry:
  878. *  None
  879. *
  880. *Exit:
  881. *  None
  882. *
  883. ***********************************************************************/
  884. void PASCAL
  885. CPoly::Quit()
  886. {
  887.     g_fQuit = 1;
  888. }
  889.  
  890. /***
  891. *void CPoly::PolyDraw(void)
  892. *Purpose:
  893. *  Draw all polygons.
  894. *
  895. *Entry:
  896. *  None
  897. *
  898. *Exit:
  899. *  None
  900. *
  901. ***********************************************************************/
  902. void
  903. CPoly::PolyDraw()
  904. {
  905.     POLYLINK FAR* polylink;
  906.  
  907.     for(polylink = g_ppolylink;
  908.     polylink != (POLYLINK FAR*)NULL;
  909.     polylink = polylink->next)
  910.     {
  911.       polylink->ppoly->Draw();
  912.     }
  913. }
  914.  
  915.  
  916. /***
  917. *void PolyTerm(void)
  918. *Purpose:
  919. *  Release all polygons.
  920. *
  921. *Entry:
  922. *  None
  923. *
  924. *Exit:
  925. *  None
  926. *
  927. ***********************************************************************/
  928. void
  929. CPoly::PolyTerm()
  930. {
  931.     POLYLINK FAR* ppolylink;
  932.     POLYLINK FAR* ppolylinkNext;
  933.  
  934.     for(ppolylink = g_ppolylink;
  935.     ppolylink != (POLYLINK FAR*)NULL;
  936.     ppolylink = ppolylinkNext)
  937.     {
  938.       ppolylinkNext = ppolylink->next;
  939.       ppolylink->ppoly->Release();
  940.       delete ppolylink;
  941.     }
  942.     g_ppolylink = NULL;
  943. }
  944.  
  945.  
  946. /***
  947. *void PolyDump(void)
  948. *Purpose:
  949. *  Invoke the debug Dump() method on all polygons were currently
  950. *  holding on to.
  951. *
  952. *Entry:
  953. *  None
  954. *
  955. *Exit:
  956. *  None
  957. *
  958. ***********************************************************************/
  959. void
  960. CPoly::PolyDump()
  961. {
  962.     POLYLINK FAR* ppolylink;
  963.  
  964.     if(g_ppolylink == (POLYLINK FAR*)NULL){
  965. #ifndef _MAC
  966.       OutputDebugString(TSTR("\t(none)\n"));
  967. #endif
  968.       return;
  969.     }
  970.  
  971.     for(ppolylink = g_ppolylink;
  972.     ppolylink != (POLYLINK FAR*)NULL;
  973.     ppolylink = ppolylink->next)
  974.     {
  975.       ppolylink->ppoly->Dump();
  976.     }
  977. }
  978.  
  979.  
  980. //---------------------------------------------------------------------
  981. //             Implementation of the CPoly Class Factory 
  982. //---------------------------------------------------------------------
  983.  
  984.  
  985. CPolyCF::CPolyCF()
  986. {
  987.     m_refs = 0;
  988. }
  989.  
  990. IClassFactory FAR*
  991. CPolyCF::Create()
  992. {
  993.     CPolyCF FAR* pCF;
  994.  
  995.     if((pCF = new FAR CPolyCF()) == NULL)
  996.       return NULL;
  997.     pCF->AddRef();
  998.     return pCF;
  999. }
  1000.  
  1001. STDMETHODIMP
  1002. CPolyCF::QueryInterface(REFIID riid, void FAR* FAR* ppv) 
  1003. {
  1004.     if(!IsEqualIID(riid, IID_IUnknown)){
  1005.       if(!IsEqualIID(riid, IID_IClassFactory)){
  1006.     *ppv = NULL;
  1007.         return E_NOINTERFACE;
  1008.       }
  1009.     }
  1010.  
  1011.     *ppv = this;
  1012.     ++m_refs;
  1013.     return NOERROR;
  1014. }
  1015.  
  1016. STDMETHODIMP_(unsigned long)
  1017. CPolyCF::AddRef(void)
  1018. {
  1019.     return ++m_refs;
  1020. }
  1021.  
  1022. STDMETHODIMP_(unsigned long)
  1023. CPolyCF::Release(void)
  1024. {
  1025.     if(--m_refs == 0){
  1026.       delete this;
  1027.       return 0;
  1028.     }
  1029.     return m_refs;
  1030. }
  1031.  
  1032. STDMETHODIMP
  1033. CPolyCF::CreateInstance(
  1034.     IUnknown FAR* punkOuter,
  1035.     REFIID iid,
  1036.     void FAR* FAR* ppv)
  1037. {
  1038.     HRESULT hresult;
  1039.     CPoly FAR *ppoly;
  1040.  
  1041.     UNUSED(punkOuter);
  1042.  
  1043. #ifdef _MAC
  1044.     if(GetZone() != ApplicZone()){
  1045. #ifndef _MSC_VER
  1046. #ifndef ConstStr255Param
  1047. #define ConstStr255Param StringPtr
  1048. #endif
  1049. #endif
  1050.       DebugStr((ConstStr255Param)"\pZones do not match");
  1051.     }
  1052.     
  1053. #endif
  1054.  
  1055.     if((ppoly = CPoly::Create()) == NULL){
  1056.       *ppv = NULL;
  1057.       return E_OUTOFMEMORY;
  1058.     }
  1059.     hresult = ppoly->QueryInterface(iid, ppv);
  1060.     ppoly->Release();
  1061.     return hresult;
  1062. }
  1063.  
  1064. STDMETHODIMP
  1065. #ifdef _MAC
  1066. CPolyCF::LockServer(unsigned long fLock)
  1067. #else
  1068. CPolyCF::LockServer(BOOL fLock)
  1069. #endif
  1070. {
  1071.     UNUSED(fLock);
  1072.  
  1073.     return NOERROR;
  1074. }
  1075.