home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap05 / polyline / ipolylin.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  23KB  |  1,054 lines

  1. /*
  2.  * IPOLYLIN.CPP
  3.  * Polyline Component Chapter 5
  4.  *
  5.  * Implementation of the IPolyline5 interface that we expose on the
  6.  * CPolyline object.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "polyline.h"
  17.  
  18.  
  19. /*
  20.  * CImpIPolyline:CImpIPolyline
  21.  * CImpIPolyline::~CImpIPolyline
  22.  *
  23.  * Constructor Parameters:
  24.  *  pObj            PCPolyline pointing to the object we live in.
  25.  *  pUnkOuter       LPUNKNOWN of the controlling unknown.
  26.  */
  27.  
  28. CImpIPolyline::CImpIPolyline(PCPolyline pObj, LPUNKNOWN pUnkOuter)
  29.     {
  30.     m_cRef=0;
  31.     m_pObj=pObj;
  32.     m_pUnkOuter=pUnkOuter;
  33.     return;
  34.     }
  35.  
  36.  
  37. CImpIPolyline::~CImpIPolyline(void)
  38.     {
  39.     return;
  40.     }
  41.  
  42.  
  43.  
  44.  
  45. /*
  46.  * CImpIPolyline::QueryInterface
  47.  * CImpIPolyline::AddRef
  48.  * CImpIPolyline::Release
  49.  */
  50.  
  51. STDMETHODIMP CImpIPolyline::QueryInterface(REFIID riid, PPVOID ppv)
  52.     {
  53.     return m_pUnkOuter->QueryInterface(riid, ppv);
  54.     }
  55.  
  56. STDMETHODIMP_(ULONG) CImpIPolyline::AddRef(void)
  57.     {
  58.     ++m_cRef;
  59.     return m_pUnkOuter->AddRef();
  60.     }
  61.  
  62. STDMETHODIMP_(ULONG) CImpIPolyline::Release(void)
  63.     {
  64.     --m_cRef;
  65.     return m_pUnkOuter->Release();
  66.     }
  67.  
  68.  
  69.  
  70.  
  71.  
  72. /*
  73.  * CImpIPolyline::Init
  74.  *
  75.  * Purpose:
  76.  *  Instantiates a polyline window within a given parent.  The
  77.  *  parent may be a main application window, could be an MDI child
  78.  *  window. We really do not care.
  79.  *
  80.  * Parameters:
  81.  *  hWndParent      HWND of the parent of this window
  82.  *  pRect           LPRECT that this window should occupy
  83.  *  dwStyle         DWORD containing the window's style flags
  84.  *  uID             UINT ID to associate with this window
  85.  *
  86.  * Return Value:
  87.  *  HRESULT         NOERROR if successful, otherwise E_OUTOFMEMORY
  88.  */
  89.  
  90. STDMETHODIMP CImpIPolyline::Init(HWND hWndParent, LPRECT pRect
  91.     , DWORD dwStyle, UINT uID)
  92.     {
  93.     SCODE           sc;
  94.  
  95.     m_pObj->m_hWnd=CreateWindowEx(WS_EX_NOPARENTNOTIFY
  96.         , SZCLASSPOLYLINE, SZCLASSPOLYLINE, dwStyle, pRect->left
  97.         , pRect->top, pRect->right-pRect->left
  98.         , pRect->bottom-pRect->top, hWndParent, (HMENU)uID
  99.         , m_pObj->m_hInst, m_pObj);
  100.  
  101.     sc=(NULL!=m_pObj->m_hWnd) ? S_OK : E_OUTOFMEMORY;
  102.     return ResultFromScode(sc);
  103.     }
  104.  
  105.  
  106.  
  107.  
  108.  
  109. /*
  110.  * CImpIPolyline::ReadFromFile
  111.  *
  112.  * Purpose:
  113.  *  Loads our current version data from a file.
  114.  *
  115.  * Parameters:
  116.  *  pszFile         LPTSTR of the file to read.
  117.  *
  118.  * Return Value:
  119.  *  HRESULT         NOERROR on success, error code otherwise.
  120.  */
  121.  
  122. STDMETHODIMP CImpIPolyline::ReadFromFile(LPTSTR pszFile)
  123.     {
  124.     OFSTRUCT        of;
  125.     HFILE           hFile;
  126.     POLYLINEDATA    pl;
  127.     UINT            cb;
  128.    #ifdef UNICODE
  129.     CHAR            szTemp[CCHPATHMAX];
  130.    #endif
  131.  
  132.     if (NULL==pszFile)
  133.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  134.  
  135.    #ifdef UNICODE
  136.     UNICODETOANSI(pszFile, szTemp, CCHPATHMAX);
  137.     hFile=OpenFile(szTemp, &of, OF_READ);
  138.    #else
  139.     hFile=OpenFile(pszFile, &of, OF_READ);
  140.    #endif
  141.  
  142.     if (HFILE_ERROR==hFile)
  143.         return ResultFromScode(POLYLINE_E_READFAILURE);
  144.  
  145.     //Since we only support one version, read all data we expect.
  146.  
  147.     //Read version numbers and seek back to file beginning.
  148.     cb=_lread(hFile, &pl, CBPOLYLINEDATA);
  149.     _lclose(hFile);
  150.  
  151.     if (CBPOLYLINEDATA!=cb)
  152.         return ResultFromScode(POLYLINE_E_READFAILURE);
  153.  
  154.     /*
  155.      * If we loaded successfully, make the data current.  By using
  156.      * DataSet we centralize our version upgrading.  We size the
  157.      * polyline window to the data AND notify the document so it
  158.      * sizes to the polyline.
  159.      */
  160.     DataSet(&pl, TRUE, TRUE);
  161.     m_pObj->m_fDirty=FALSE;
  162.     return NOERROR;
  163.     }
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170. /*
  171.  * CImpIPolyline::WriteToFile
  172.  *
  173.  * Purpose:
  174.  *  Ignorantly writes our current data into a file overwriting
  175.  *  previous contents.
  176.  *
  177.  * Parameters:
  178.  *  pszFile         LPTSTR file in which to write.
  179.  *
  180.  * Return Value:
  181.  *  HRESULT         NOERROR if successful, otherwise a
  182.  *                  POLYLINE_E_ value.
  183.  */
  184.  
  185. STDMETHODIMP CImpIPolyline::WriteToFile(LPTSTR pszFile)
  186.     {
  187.     OFSTRUCT        of;
  188.     HFILE           hFile;
  189.     POLYLINEDATA    pl;
  190.     UINT            cb;
  191.    #ifdef UNICODE
  192.     CHAR            szTemp[CCHPATHMAX];
  193.    #endif
  194.  
  195.     if (NULL==pszFile)
  196.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  197.  
  198.    #ifdef UNICODE
  199.     UNICODETOANSI(pszFile, szTemp, CCHPATHMAX);
  200.     hFile=OpenFile(szTemp, &of, OF_CREATE | OF_WRITE);
  201.    #else
  202.     hFile=OpenFile(pszFile, &of, OF_CREATE | OF_WRITE);
  203.    #endif
  204.  
  205.     if (HFILE_ERROR==hFile)
  206.         return ResultFromScode(POLYLINE_E_WRITEFAILURE);
  207.  
  208.     DataGet(&pl);
  209.     cb=_lwrite(hFile, (LPCSTR)&pl, CBPOLYLINEDATA);
  210.     _lclose(hFile);
  211.  
  212.     m_pObj->m_fDirty=!(CBPOLYLINEDATA==cb);
  213.  
  214.     return (!m_pObj->m_fDirty) ?
  215.         NOERROR : ResultFromScode(POLYLINE_E_WRITEFAILURE);
  216.     }
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226. /*
  227.  * CImpIPolyline::DataSet
  228.  *
  229.  * Purpose:
  230.  *  Sets the current data in this Polyline to a given structure.
  231.  *
  232.  * Parameters:
  233.  *  pplIn           PPOLYLINEDATA to initialize to.
  234.  *  fSizeToData     BOOL indicating if we're to size to the data
  235.  *                  or scale it.
  236.  *  fNotify         BOOL indicating if we're to send an advise
  237.  *                  on this change.
  238.  *
  239.  * Return Value:
  240.  *  HRESULT         NOERROR if successful, otherwise a
  241.  *                  POLYLINE_E_ value.
  242.  */
  243.  
  244. STDMETHODIMP CImpIPolyline::DataSet(PPOLYLINEDATA pplIn
  245.     , BOOL fSizeToData, BOOL fNotify)
  246.     {
  247.     PPOLYLINEDATA   ppl=&m_pObj->m_pl;
  248.     RECT            rc;
  249.  
  250.     /*
  251.      * Copy the structure in pplIn and repaint to reflect the
  252.      * new point set.  Note that unlike the RectSet message, we
  253.      * do no scaling, assuming that the rect in the structure
  254.      * is appropriate for the data.
  255.      */
  256.  
  257.     if (NULL==pplIn)
  258.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  259.  
  260.     *ppl=*pplIn;
  261.  
  262.     //Inform our parent of the data change
  263.     if (NULL!=m_pObj->m_pAdv)
  264.         {
  265.         m_pObj->m_fDirty=TRUE;
  266.         m_pObj->m_pAdv->OnDataChange();
  267.         }
  268.  
  269.     /*
  270.      * If we're scaling the window to fit the data, then use
  271.      * RectSet passing our current rectangle as the new one.
  272.      * That makes sure that the data won't change but that the
  273.      * window is resized.
  274.      */
  275.  
  276.     if (fSizeToData)
  277.         {
  278.         POINT       pt;
  279.  
  280.         /*
  281.          * Get our offset in the parent window so we can RectSet
  282.          * to the right place since RectSet expects rectangle in
  283.          * parent coordinates and we get it in client coordinates.
  284.          */
  285.         GetWindowRect(m_pObj->m_hWnd, &rc);
  286.         pt.x=rc.left;
  287.         pt.y=rc.top;
  288.         ScreenToClient(GetParent(m_pObj->m_hWnd), &pt);
  289.         RECTSTORECT(ppl->rc, rc);
  290.         OffsetRect(&rc, pt.x, pt.y);
  291.  
  292.         //This will also cause a repaint.
  293.         RectSet(&rc, fNotify);
  294.         }
  295.     else
  296.         {
  297.         //Make sure we're updated.
  298.         InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  299.         UpdateWindow(m_pObj->m_hWnd);
  300.         }
  301.  
  302.     return NOERROR;
  303.     }
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311. /*
  312.  * CImpIPolyline::DataGet
  313.  *
  314.  * Purpose:
  315.  *  Retrieves the Polyline's current data.
  316.  *
  317.  * Parameters:
  318.  *  pplIn           PPOLYLINEDATA into which we copy the data.
  319.  *
  320.  * Return Value:
  321.  *  HRESULT         NOERROR if successful, otherwise a
  322.  *                  POLYLINE_E_ value.
  323.  */
  324.  
  325. STDMETHODIMP CImpIPolyline::DataGet(PPOLYLINEDATA pplIn)
  326.     {
  327.     if (NULL==pplIn)
  328.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  329.  
  330.     *pplIn=m_pObj->m_pl;
  331.     return NOERROR;
  332.     }
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340. /*
  341.  * CImpIPolyline::DataSetMem
  342.  *
  343.  * Purpose:
  344.  *  Sets the Polyline's data using a global memory handle
  345.  *  instead of a pointer.
  346.  *
  347.  * Parameters:
  348.  *  hMem            HGLOBAL containing the data.
  349.  *  fFree           BOOL indicating if we're to free the data.
  350.  *                  The memory will be freed regardless of any
  351.  *                  error returned from here.
  352.  *  fSizeToData     BOOL indicating if we're to size to the data
  353.  *                  or scale it.
  354.  *  fNotify         BOOL indicating if we're to send an advise
  355.  *                  on this change.
  356.  *
  357.  * Return Value:
  358.  *  HRESULT         NOERROR if successful, otherwise a
  359.  *                  POLYLINE_E_ value.
  360.  */
  361.  
  362. STDMETHODIMP CImpIPolyline::DataSetMem(HGLOBAL hMem, BOOL fFree
  363.     , BOOL fSizeToData, BOOL fNotify)
  364.     {
  365.     PPOLYLINEDATA   ppl;
  366.     HRESULT         hr=ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  367.  
  368.     if (NULL!=hMem)
  369.         {
  370.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  371.         hr=DataSet(ppl, fSizeToData, fNotify);
  372.  
  373.         GlobalUnlock(hMem);
  374.  
  375.         if (fFree)
  376.             GlobalFree(hMem);
  377.         }
  378.  
  379.     return hr;
  380.     }
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388. /*
  389.  * CImpIPolyline::DataGetMem
  390.  *
  391.  * Purpose:
  392.  *  Retrieves the Polyline's data in a global memory handle.
  393.  *
  394.  * Parameters:
  395.  *  phMem           HGLOBAL * in which to store the handle.
  396.  *
  397.  * Return Value:
  398.  *  HRESULT         NOERROR if successful, otherwise a
  399.  *                  POLYLINE_E_ value.
  400.  */
  401.  
  402. STDMETHODIMP CImpIPolyline::DataGetMem(HGLOBAL *phMem)
  403.     {
  404.     HGLOBAL         hMem;
  405.     PPOLYLINEDATA   ppl;
  406.     HRESULT         hr=ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  407.  
  408.     if (NULL==phMem)
  409.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  410.  
  411.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, CBPOLYLINEDATA);
  412.  
  413.     if (NULL!=hMem)
  414.         {
  415.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  416.         hr=DataGet(ppl);
  417.  
  418.         GlobalUnlock(hMem);
  419.  
  420.         if (FAILED(hr))
  421.             {
  422.             GlobalFree(hMem);
  423.             hMem=NULL;
  424.             }
  425.         }
  426.  
  427.     *phMem=hMem;
  428.     return hr;
  429.     }
  430.  
  431.  
  432.  
  433.  
  434. /*
  435.  * CImpIPolyline::RenderBitmap
  436.  *
  437.  * Purpose:
  438.  *  Creates a bitmap image of the current Polyline.
  439.  *
  440.  * Parameters:
  441.  *  phBmp           HBITMAP * in which to return the bitmap.
  442.  *
  443.  * Return Value:
  444.  *  HRESULT         NOERROR if successful, otherwise a
  445.  *                  POLYLINE_E_ value.
  446.  */
  447.  
  448. STDMETHODIMP CImpIPolyline::RenderBitmap(HBITMAP *phBmp)
  449.     {
  450.     HDC             hDC;
  451.     HDC             hMemDC;
  452.     HBITMAP         hBmp;
  453.     RECT            rc;
  454.     HGDIOBJ         hObj;
  455.  
  456.     if (NULL==phBmp)
  457.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  458.  
  459.     //Render a bitmap the size of the current rectangle.
  460.     hDC=GetDC(m_pObj->m_hWnd);
  461.     hMemDC=CreateCompatibleDC(hDC);
  462.  
  463.     GetClientRect(m_pObj->m_hWnd, &rc);
  464.     hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  465.  
  466.     if (NULL!=hBmp)
  467.         {
  468.         //Draw the POLYLINEDATA into the bitmap.
  469.         hObj=SelectObject(hMemDC, hBmp);
  470.         m_pObj->Draw(hMemDC, FALSE, TRUE);
  471.         SelectObject(hMemDC, hObj);
  472.         }
  473.  
  474.     DeleteDC(hMemDC);
  475.     ReleaseDC(m_pObj->m_hWnd, hDC);
  476.  
  477.     *phBmp=hBmp;
  478.     return NOERROR;
  479.     }
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487. /*
  488.  * CImpIPolyline::RenderMetafile
  489.  *
  490.  * Purpose:
  491.  *  Renders the current image of the Polyline into a metafile.
  492.  *
  493.  * Parameters:
  494.  *  phMF            HMETAFILE * in which to return the
  495.  *                  new metafile.
  496.  *
  497.  * Return Value:
  498.  *  HRESULT         NOERROR if successful, otherwise a
  499.  *                  POLYLINE_E_ value.
  500.  */
  501.  
  502. STDMETHODIMP CImpIPolyline::RenderMetafile(HMETAFILE *phMF)
  503.     {
  504.     HDC             hDC;
  505.     HMETAFILE       hMF;
  506.     RECT            rc;
  507.  
  508.     if (NULL==phMF)
  509.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  510.  
  511.     //Create a memory metafile and return its handle.
  512.     hDC=(HDC)CreateMetaFile(NULL);
  513.     hMF=NULL;
  514.  
  515.     if (NULL!=hDC)
  516.         {
  517.         /*
  518.          * This is absolutely essential to the metafile so it
  519.          * can be scaled in the clipboard and any destination
  520.          * application.
  521.          */
  522.         SetMapMode(hDC, MM_ANISOTROPIC);
  523.         GetClientRect(m_pObj->m_hWnd, &rc);
  524.         SetWindowOrgEx(hDC, 0, 0, NULL);
  525.         SetWindowExtEx(hDC, rc.right, rc.bottom, NULL);
  526.  
  527.         m_pObj->Draw(hDC, TRUE, TRUE);
  528.         hMF=CloseMetaFile(hDC);
  529.         }
  530.  
  531.     *phMF=hMF;
  532.     return NOERROR;
  533.     }
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540. /*
  541.  * CImpIPolyline::RenderMetafilePict
  542.  *
  543.  * Purpose:
  544.  *  Renders the current Polyline into a METAFILEPICT structure in
  545.  *  global memory.
  546.  *
  547.  * Parameters:
  548.  *  phMem           HGLOBAL * in which to return the
  549.  *                  METAFILEPICT.
  550.  *
  551.  * Return Value:
  552.  *  HRESULT         NOERROR if successful, otherwise a
  553.  *                  POLYLINE_E_ value.
  554.  */
  555.  
  556. STDMETHODIMP CImpIPolyline::RenderMetafilePict(HGLOBAL *phMem)
  557.     {
  558.     HGLOBAL         hMem;
  559.     HMETAFILE       hMF;
  560.     LPMETAFILEPICT  pMF;
  561.     RECT            rc;
  562.     HRESULT         hr;
  563.  
  564.     if (NULL==phMem)
  565.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  566.  
  567.     //Get the metafile
  568.     hr=RenderMetafile(&hMF);
  569.  
  570.     if (FAILED(hr))
  571.         return hr;
  572.  
  573.     //Allocate the METAFILEPICT structure.
  574.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  575.         , sizeof(METAFILEPICT));
  576.  
  577.     if (NULL==hMem)
  578.         {
  579.         DeleteMetaFile(hMF);
  580.         return ResultFromScode(E_FAIL);
  581.         }
  582.  
  583.     /*
  584.      * Global lock only fails in PMODE if the selector is invalid
  585.      * (like it was discarded) or references a 0 length segment,
  586.      * neither of which can happen here.
  587.      */
  588.     pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  589.  
  590.     pMF->hMF=hMF;
  591.     pMF->mm=MM_ANISOTROPIC;
  592.  
  593.     //Insert the extents in MM_HIMETRIC units.
  594.     GetClientRect(m_pObj->m_hWnd, &rc);
  595.     m_pObj->RectConvertMappings(&rc, FALSE);
  596.     pMF->xExt=rc.right;
  597.     pMF->yExt=rc.bottom;
  598.  
  599.     GlobalUnlock(hMem);
  600.  
  601.     *phMem=hMem;
  602.     return NOERROR;
  603.     }
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613. /*
  614.  * CImpIPolyline::New
  615.  *
  616.  * Purpose:
  617.  *  Cleans out and reinitializes the data to defaults.
  618.  *
  619.  * Parameters:
  620.  *  None
  621.  *
  622.  * Return Value:
  623.  *  HRESULT         NOERROR always
  624.  */
  625.  
  626. STDMETHODIMP CImpIPolyline::New(void)
  627.     {
  628.     PPOLYLINEDATA   ppl=&m_pObj->m_pl;
  629.     UINT            i;
  630.     RECT            rc;
  631.  
  632.     ppl->wVerMaj=VERSIONMAJOR;
  633.     ppl->wVerMin=VERSIONMINOR;
  634.  
  635.     //Our rectangle is the size of our window's client area.
  636.     GetClientRect(m_pObj->m_hWnd, &rc);
  637.     RECTTORECTS(rc, ppl->rc);
  638.  
  639.     //Clean out the POLYLINEDATA structure and repaint the window.
  640.     for (i=0; i< CPOLYLINEPOINTS; i++)
  641.         {
  642.         ppl->rgpt[i].x=0;
  643.         ppl->rgpt[i].y=0;
  644.         }
  645.  
  646.     ppl->cPoints      =0;
  647.     ppl->rgbBackground=GetSysColor(COLOR_WINDOW);
  648.     ppl->rgbLine      =GetSysColor(COLOR_WINDOWTEXT);
  649.     ppl->iLineStyle   =PS_SOLID;
  650.  
  651.     InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  652.     UpdateWindow(m_pObj->m_hWnd);
  653.  
  654.     //Inform the advise sink of this data change.
  655.     if (NULL!=m_pObj->m_pAdv)
  656.         {
  657.         m_pObj->m_fDirty=TRUE;
  658.         m_pObj->m_pAdv->OnDataChange();
  659.         }
  660.  
  661.     return NOERROR;
  662.     }
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669. /*
  670.  * CImpIPolyline::Undo
  671.  *
  672.  * Purpose:
  673.  *  Reverses previous actions in a Polyline.
  674.  *
  675.  * Parameters:
  676.  *  None
  677.  *
  678.  * Return Value:
  679.  *  HRESULT         S_OK if we can Undo more, S_FALSE otherwise.
  680.  */
  681.  
  682. STDMETHODIMP CImpIPolyline::Undo(void)
  683.     {
  684.     SCODE           sc;
  685.  
  686.     //Decrement the number of active points and repaint.
  687.     if (m_pObj->m_pl.cPoints > 0)
  688.         {
  689.         m_pObj->m_pl.cPoints--;
  690.         InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  691.         UpdateWindow(m_pObj->m_hWnd);
  692.         }
  693.  
  694.     if (NULL!=m_pObj->m_pAdv)
  695.         {
  696.         m_pObj->m_fDirty=TRUE;
  697.         m_pObj->m_pAdv->OnPointChange();
  698.         }
  699.  
  700.     //Return if we can undo any more.
  701.     sc=(0!=m_pObj->m_pl.cPoints) ? S_OK : S_FALSE;
  702.     return ResultFromScode(sc);
  703.     }
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710. /*
  711.  * CImpIPolyline::Window
  712.  *
  713.  * Purpose:
  714.  *  Returns the window handle associated with this polyline.
  715.  *
  716.  * Parameters:
  717.  *  phWnd           HWND * in which to return the window handle.
  718.  *
  719.  * Return Value:
  720.  *  HRESULT         NOERROR always.
  721.  */
  722.  
  723. STDMETHODIMP CImpIPolyline::Window(HWND *phWnd)
  724.     {
  725.     *phWnd=m_pObj->m_hWnd;
  726.     return NOERROR;
  727.     }
  728.  
  729.  
  730.  
  731.  
  732.  
  733.  
  734. /*
  735.  * CImpIPolyline::RectGet
  736.  *
  737.  * Purpose:
  738.  *  Returns the rectangle of the Polyline in parent coordinates.
  739.  *
  740.  * Parameters:
  741.  *  pRect           LPRECT in which to return the rectangle.
  742.  *
  743.  * Return Value:
  744.  *  HRESULT         NOERROR always
  745.  */
  746.  
  747. STDMETHODIMP CImpIPolyline::RectGet(LPRECT pRect)
  748.     {
  749.     RECT            rc;
  750.     POINT           pt;
  751.  
  752.     //Retrieve the size of our rectangle in parent coordinates.
  753.     GetWindowRect(m_pObj->m_hWnd, &rc);
  754.     pt.x=rc.left;
  755.     pt.y=rc.top;
  756.     ScreenToClient(GetParent(m_pObj->m_hWnd), &pt);
  757.  
  758.     SetRect(pRect, pt.x, pt.y, pt.x+(rc.right-rc.left)
  759.         , pt.y+(rc.bottom-rc.top));
  760.  
  761.     return NOERROR;
  762.     }
  763.  
  764.  
  765.  
  766.  
  767.  
  768. /*
  769.  * CImpIPolyline::SizeGet
  770.  *
  771.  * Purpose:
  772.  *  Retrieves the size of the Polyline in parent coordinates.
  773.  *
  774.  * Parameters:
  775.  *  pRect           LPRECT in which to return the size.  The right
  776.  *                  and bottom fields will contain the dimensions.
  777.  *
  778.  * Return Value:
  779.  *  HRESULT         NOERROR always
  780.  */
  781.  
  782. STDMETHODIMP CImpIPolyline::SizeGet(LPRECT pRect)
  783.     {
  784.     RectGet(pRect);
  785.     return NOERROR;
  786.     }
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793. /*
  794.  * CImpIPolyline::RectSet
  795.  *
  796.  * Purpose:
  797.  *  Sets a new rectangle for the Polyline which sizes to fit.
  798.  *
  799.  * Parameters:
  800.  *  pRect           LPRECT containing the new rectangle.
  801.  *  fNotify         BOOL indicating if we're to notify anyone of
  802.  *                  the change.
  803.  *
  804.  * Return Value:
  805.  *  HRESULT         NOERROR always
  806.  */
  807.  
  808. STDMETHODIMP CImpIPolyline::RectSet(LPRECT pRect, BOOL fNotify)
  809.     {
  810.     UINT            cx, cy;
  811.     RECT            rc;
  812.  
  813.     //Scale the points from our current size to the new size
  814.     cx=pRect->right-pRect->left;
  815.     cy=pRect->bottom-pRect->top;
  816.  
  817.     SetWindowPos(m_pObj->m_hWnd, NULL, pRect->left, pRect->top
  818.         , cx, cy, SWP_NOZORDER);
  819.  
  820.     SetRect(&rc, 0, 0, cx, cy);
  821.     RECTTORECTS(rc, m_pObj->m_pl.rc);
  822.  
  823.     if (fNotify && NULL!=m_pObj->m_pAdv)
  824.         {
  825.         m_pObj->m_fDirty=TRUE;
  826.         m_pObj->m_pAdv->OnSizeChange();
  827.         }
  828.  
  829.     InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  830.  
  831.     return NOERROR;
  832.     }
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840. /*
  841.  * CImpIPolyline::SizeSet
  842.  *
  843.  * Purpose:
  844.  *  Sets a new size for the Polyline which sizes to fit.
  845.  *
  846.  * Parameters:
  847.  *  pRect           LPRECT containing the new rectangle.
  848.  *  fNotify         BOOL indicating if we're to notify anyone of
  849.  *                  the change.
  850.  *
  851.  * Return Value:
  852.  *  HRESULT         NOERROR always
  853.  */
  854.  
  855. STDMETHODIMP CImpIPolyline::SizeSet(LPRECT pRect, BOOL fNotify)
  856.     {
  857.     UINT            cx, cy;
  858.  
  859.     //Scale the points from our current size to the new size
  860.     cx=pRect->right-pRect->left;
  861.     cy=pRect->bottom-pRect->top;
  862.  
  863.     SetWindowPos(m_pObj->m_hWnd, NULL, 0, 0, (UINT)cx, (UINT)cy
  864.         , SWP_NOMOVE | SWP_NOZORDER);
  865.  
  866.     if (fNotify && NULL!=m_pObj->m_pAdv)
  867.         {
  868.         m_pObj->m_fDirty=TRUE;
  869.         m_pObj->m_pAdv->OnSizeChange();
  870.         }
  871.  
  872.     InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  873.  
  874.     return NOERROR;
  875.     }
  876.  
  877.  
  878.  
  879.  
  880.  
  881.  
  882. /*
  883.  * CImpIPolyline::ColorSet
  884.  *
  885.  * Purpose:
  886.  *  Changes for background or line color in the Polyline
  887.  *
  888.  * Parameters:
  889.  *  iColor          UINT index of the color to change.
  890.  *  cr              COLORREF new color to use.
  891.  *  pcrPrev         COLORREF * in whch to store the
  892.  *                  previous color.
  893.  *
  894.  * Return Value:
  895.  *  HRESULT         NOERROR if successful, otherwise a
  896.  *                  POLYLINE_E_ value.
  897.  */
  898.  
  899. STDMETHODIMP CImpIPolyline::ColorSet(UINT iColor, COLORREF cr
  900.     , COLORREF *pcrPrev)
  901.     {
  902.     COLORREF        crRet;
  903.  
  904.     if (NULL==pcrPrev)
  905.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  906.  
  907.     switch (iColor)
  908.         {
  909.         case POLYLINECOLOR_BACKGROUND:
  910.             crRet=m_pObj->m_pl.rgbBackground;
  911.             m_pObj->m_pl.rgbBackground=cr;
  912.             break;
  913.  
  914.         case POLYLINECOLOR_LINE:
  915.             crRet=m_pObj->m_pl.rgbLine;
  916.             m_pObj->m_pl.rgbLine=cr;
  917.             break;
  918.         }
  919.  
  920.     //If the color changed, repaint
  921.     if (crRet!=cr)
  922.         {
  923.         if (NULL!=m_pObj->m_pAdv)
  924.             {
  925.             m_pObj->m_fDirty=TRUE;
  926.             m_pObj->m_pAdv->OnColorChange();
  927.             }
  928.  
  929.         InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  930.         UpdateWindow(m_pObj->m_hWnd);
  931.         }
  932.  
  933.     *pcrPrev=crRet;
  934.     return NOERROR;
  935.     }
  936.  
  937.  
  938.  
  939.  
  940.  
  941.  
  942.  
  943. /*
  944.  * CImpIPolyline::ColorGet
  945.  *
  946.  * Purpose:
  947.  *  Retrieves one of the colors currently in use by the Polyline.
  948.  *
  949.  * Parameters:
  950.  *  iColor          UINT identifying the color of interest.
  951.  *  pcr             COLORREF * in which to return the color.
  952.  *
  953.  * Return Value:
  954.  *  HRESULT         NOERROR if successful, otherwise a
  955.  *                  POLYLINE_E_ value.
  956.  */
  957.  
  958. STDMETHODIMP CImpIPolyline::ColorGet(UINT iColor, COLORREF *pcr)
  959.     {
  960.     COLORREF        crRet;
  961.  
  962.     if (NULL==pcr)
  963.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  964.  
  965.     crRet=(POLYLINECOLOR_BACKGROUND==iColor)
  966.         ? m_pObj->m_pl.rgbBackground : m_pObj->m_pl.rgbLine;
  967.  
  968.     *pcr=crRet;
  969.     return NOERROR;
  970.     }
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979. /*
  980.  * CImpIPolyline::LineStyleSet
  981.  *
  982.  * Purpose:
  983.  *  Changes the line style in use by the Polyline
  984.  *
  985.  * Parameters:
  986.  *  iStyle          UINT style of the line to use.
  987.  *  piPrev          UINT * in which to store the previous style.
  988.  *
  989.  * Return Value:
  990.  *  HRESULT         NOERROR if successful, otherwise a
  991.  *                  POLYLINE_E_ value.
  992.  */
  993.  
  994. STDMETHODIMP CImpIPolyline::LineStyleSet(UINT iStyle, UINT *piPrev)
  995.     {
  996.     UINT            uRet;
  997.  
  998.     uRet=(UINT)m_pObj->m_pl.iLineStyle;
  999.  
  1000.     if (NULL==piPrev)
  1001.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  1002.  
  1003.     //Validate the line style
  1004.     if (PS_SOLID==iStyle || PS_DASH==iStyle || PS_DOT==iStyle
  1005.         || PS_DASHDOT==iStyle || PS_DASHDOTDOT==iStyle)
  1006.         {
  1007.         m_pObj->m_pl.iLineStyle=iStyle;
  1008.  
  1009.         if (uRet!=(UINT)m_pObj->m_pl.iLineStyle)
  1010.             {
  1011.             if (NULL!=m_pObj->m_pAdv)
  1012.                 {
  1013.                 m_pObj->m_fDirty=TRUE;
  1014.                 m_pObj->m_pAdv->OnLineStyleChange();
  1015.                 }
  1016.  
  1017.             InvalidateRect(m_pObj->m_hWnd, NULL, TRUE);
  1018.             UpdateWindow(m_pObj->m_hWnd);
  1019.             }
  1020.         }
  1021.  
  1022.     *piPrev=uRet;
  1023.     return NOERROR;
  1024.     }
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032. /*
  1033.  * CImpIPolyline::LineStyleGet
  1034.  *
  1035.  * Purpose:
  1036.  *  Retrieves the current line style in use in the Polyline
  1037.  *
  1038.  * Parameters:
  1039.  *  piStyle         UINT * in which to store the style.
  1040.  *
  1041.  * Return Value:
  1042.  *  HRESULT         NOERROR if successful, otherwise a
  1043.  *                  POLYLINE_E_ value.
  1044.  */
  1045.  
  1046. STDMETHODIMP CImpIPolyline::LineStyleGet(UINT *piStyle)
  1047.     {
  1048.     if (NULL==piStyle)
  1049.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  1050.  
  1051.     *piStyle=m_pObj->m_pl.iLineStyle;
  1052.     return NOERROR;
  1053.     }
  1054.