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 / chap23 / cosmo / polyline.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  33.0 KB  |  1,511 lines

  1. /*
  2.  * POLYLINE.CPP
  3.  * Cosmo Chapter 23
  4.  *
  5.  * Implementation of the CPolyline class.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13.  
  14.  
  15. #include "cosmo.h"
  16.  
  17.  
  18. /*
  19.  * CPolyline:CPolyline
  20.  * CPolyline::~CPolyline
  21.  *
  22.  * Constructor Parameters:
  23.  *  hInst           HINSTANCE of the application we're in.
  24.  */
  25.  
  26. CPolyline::CPolyline(HINSTANCE hInst)
  27.     : CWindow(hInst)
  28.     {
  29.     m_pAdv=NULL;
  30.     m_hWnd=NULL;
  31.     m_fReadFromOLE10=FALSE;
  32.     return;
  33.     }
  34.  
  35.  
  36. CPolyline::~CPolyline(void)
  37.     {
  38.     return;
  39.     }
  40.  
  41.  
  42.  
  43.  
  44.  
  45. /*
  46.  * CPolyline::Init
  47.  *
  48.  * Purpose:
  49.  *  Instantiates a polyline window within a given parent.  The
  50.  *  parent may be a main application window, could be an MDI child
  51.  *  window. We really do not care.
  52.  *
  53.  * Parameters:
  54.  *  hWndParent      HWND of the parent of this window
  55.  *  pRect           LPRECT that this window should occupy
  56.  *  dwStyle         DWORD containing the window's style flags
  57.  *  uID             UINT ID to associate with this window
  58.  *  pAdv            PCPolylineAdviseSink of the sink wanting our
  59.  *                  notifications.
  60.  *
  61.  * Return Value:
  62.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  63.  */
  64.  
  65. BOOL CPolyline::Init(HWND hWndParent, LPRECT pRect, DWORD dwStyle
  66.     , UINT uID, PCPolylineAdviseSink pAdv)
  67.     {
  68.     m_hWnd=CreateWindowEx(WS_EX_NOPARENTNOTIFY, SZCLASSPOLYLINE
  69.         , SZCLASSPOLYLINE, dwStyle, pRect->left, pRect->top
  70.         , pRect->right-pRect->left, pRect->bottom-pRect->top
  71.         , hWndParent, (HMENU)uID, m_hInst, this);
  72.  
  73.     if (NULL!=m_hWnd)
  74.         m_pAdv=pAdv;
  75.  
  76.     return (NULL!=m_hWnd);
  77.     }
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85. /*
  86.  * CPolyline::New
  87.  *
  88.  * Purpose:
  89.  *  Cleans out and reinitializes the data to defaults.
  90.  *
  91.  * Parameters:
  92.  *  None
  93.  *
  94.  * Return Value:
  95.  *  None
  96.  */
  97.  
  98. void CPolyline::New(void)
  99.     {
  100.     UINT        i;
  101.     RECT        rc;
  102.  
  103.     m_pl.wVerMaj=VERSIONMAJOR;
  104.     m_pl.wVerMin=VERSIONMINOR;
  105.  
  106.     //Our rectangle is the size of our window's client area.
  107.     GetClientRect(m_hWnd, &rc);
  108.     RECTTORECTS(rc, m_pl.rc);
  109.  
  110.     //Clean out the POLYLINE structure and repaint the window.
  111.     for (i=0; i< CPOLYLINEPOINTS; i++)
  112.         {
  113.         m_pl.rgpt[i].x=0;
  114.         m_pl.rgpt[i].y=0;
  115.         }
  116.  
  117.     m_pl.cPoints      =0;
  118.     m_pl.rgbBackground=GetSysColor(COLOR_WINDOW);
  119.     m_pl.rgbLine      =GetSysColor(COLOR_WINDOWTEXT);
  120.     m_pl.iLineStyle   =PS_SOLID;
  121.  
  122.     InvalidateRect(m_hWnd, NULL, TRUE);
  123.     UpdateWindow(m_hWnd);
  124.  
  125.     //Inform the advise sink of this data change.
  126.     if (NULL!=m_pAdv)
  127.         m_pAdv->OnDataChange();
  128.  
  129.     return;
  130.     }
  131.  
  132.  
  133.  
  134.  
  135. /*
  136.  * CPolyline::Undo
  137.  *
  138.  * Purpose:
  139.  *  Reverses previous actions in a Polyline.
  140.  *
  141.  * Parameters:
  142.  *  None
  143.  *
  144.  * Return Value:
  145.  *  BOOL            TRUE if we can Undo more, FALSE otherwise.
  146.  */
  147.  
  148. BOOL CPolyline::Undo(void)
  149.     {
  150.     //Decrement the number of active points and repaint.
  151.     if (m_pl.cPoints > 0)
  152.         {
  153.         m_pl.cPoints--;
  154.         InvalidateRect(m_hWnd, NULL, TRUE);
  155.         UpdateWindow(m_hWnd);
  156.         }
  157.  
  158.     if (NULL!=m_pAdv)
  159.         m_pAdv->OnPointChange();
  160.  
  161.     //Return if we can undo any more.
  162.     return (0!=m_pl.cPoints);
  163.     }
  164.  
  165.  
  166.  
  167.  
  168.  
  169. /*
  170.  * CPolyline::ReadFromStorage
  171.  *
  172.  * Purpose:
  173.  *  Loads our data (any known version) from an IStorage returning
  174.  *  the version number of the data or an error value.
  175.  *
  176.  * Parameters:
  177.  *  pIStorage       LPSTORAGE from which we'll read.
  178.  *
  179.  * Return Value:
  180.  *  LONG            Version number or negative POLYLINE_E_* value.
  181.  */
  182.  
  183. LONG CPolyline::ReadFromStorage(LPSTORAGE pIStorage)
  184.     {
  185.     LONG            lRet;
  186.     LPSTREAM        pIStream;
  187.     HRESULT         hr;
  188.  
  189.     if (NULL==pIStorage)
  190.         return POLYLINE_E_READFAILURE;
  191.  
  192.     //Open the CONTENTS stream
  193.     hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT | STGM_READ
  194.         | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  195.  
  196.     if (FAILED(hr))
  197.         return POLYLINE_E_READFAILURE;
  198.  
  199.     /*
  200.      * Since we had to create ReadFromStream for IPersistStorage,
  201.      * use it ourselves.
  202.      */
  203.     lRet=ReadFromStream(pIStream);
  204.     pIStream->Release();
  205.  
  206.     return lRet;
  207.     }
  208.  
  209.  
  210.  
  211.  
  212. /*
  213.  * CPolyline::WriteToStorage
  214.  *
  215.  * Purpose:
  216.  *  Ignorantly writes our current data into a storage in a
  217.  *  particular version.
  218.  *
  219.  * Parameters:
  220.  *  pIStorage       LPSTORAGE in which to save.
  221.  *  lVer            LONG providing version number Major (HI) and
  222.  *                  Minor (Low)
  223.  *
  224.  * Return Value:
  225.  *  LONG            A POLYLINE_E_* value.
  226.  */
  227.  
  228. LONG CPolyline::WriteToStorage(LPSTORAGE pIStorage, LONG lVer)
  229.     {
  230.     LONG            lRet;
  231.     LPSTREAM        pIStream;
  232.     HRESULT         hr;
  233.  
  234.     if (NULL==pIStorage)
  235.         return POLYLINE_E_READFAILURE;
  236.  
  237.     hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT | STGM_CREATE
  238.         | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream);
  239.  
  240.     if (FAILED(hr))
  241.         return POLYLINE_E_WRITEFAILURE;
  242.  
  243.     /*
  244.      * Use our function that will save to a stream now that
  245.      * we needed it for IPersistStorage.
  246.      */
  247.  
  248.     lRet=WriteToStream(pIStream, lVer);
  249.     pIStream->Release();
  250.  
  251.     return lRet;
  252.     }
  253.  
  254.  
  255.  
  256.  
  257. /*
  258.  * CPolyline::ReadFromStream
  259.  *
  260.  * Purpose:
  261.  *  Loads our data (any known version) from an IStream that we
  262.  *  do not open nor maintain.  This is for the compound document
  263.  *  object's implementation of IPersistStorage.
  264.  *
  265.  * Parameters:
  266.  *  pIStream        LPSTREAM from which we'll read.
  267.  *
  268.  * Return Value:
  269.  *  LONG            Version number or negative POLYLINE_E_* value.
  270.  */
  271.  
  272. LONG CPolyline::ReadFromStream(LPSTREAM pIStream)
  273.     {
  274.     POLYLINEDATA    pl;
  275.     ULONG           cb=(ULONG)-1;
  276.     ULONG           cbExpect=0;
  277.     HRESULT         hr;
  278.     LARGE_INTEGER   li;
  279.  
  280.     if (NULL==pIStream)
  281.         return POLYLINE_E_READFAILURE;
  282.  
  283.     /*
  284.      * If IPersistStorage::Load failed to find CONTENTS but did
  285.      * open "\1Ole10Native" then m_fReadFromOLE10 is set.  So
  286.      * we have to start reading past the leading DWORD.
  287.      */
  288.  
  289.     if (m_fReadFromOLE10)
  290.         {
  291.         DWORD       dw;
  292.  
  293.         /*
  294.          * Skip the DWORD length at the beginning of the
  295.          * Ole10Native stream.
  296.          */
  297.         pIStream->Read(&dw, sizeof(DWORD), &cb);
  298.         }
  299.  
  300.  
  301.     //Read version numbers and seek back to file beginning.
  302.     hr=pIStream->Read(&pl, 2*sizeof(WORD), &cb);
  303.  
  304.     //If we read OLE 1, seek back but skip the size header.
  305.     LISet32(li, m_fReadFromOLE10 ? sizeof(DWORD) : 0);
  306.     pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  307.  
  308.     if (FAILED(hr) || 2*sizeof(WORD)!=cb)
  309.         {
  310.         pIStream->Release();
  311.         return POLYLINE_E_READFAILURE;
  312.         }
  313.  
  314.     /*
  315.      * For version 2.0, read the entire file.  For version 1.0 read
  316.      * the file up to CBPOLYLINEDATAVER10.  For anything else, give
  317.      * an error.
  318.      */
  319.  
  320.     switch (pl.wVerMaj)
  321.         {
  322.         case VERSIONMAJOR:  //2.x
  323.             switch (pl.wVerMin)
  324.                 {
  325.                 case VERSIONMINOR:  //2.0
  326.                     cbExpect=CBPOLYLINEDATA;
  327.                     break;
  328.  
  329.                 default:
  330.                     break;
  331.                 }
  332.             break;
  333.  
  334.         case 1: //1.x
  335.             switch (pl.wVerMin)
  336.                 {
  337.                 case 0:  //1.0
  338.                     cbExpect=CBPOLYLINEDATA10;
  339.                     break;
  340.  
  341.                 default:
  342.                     break;
  343.                 }
  344.             break;
  345.  
  346.         default:
  347.             break;
  348.         }
  349.  
  350.     if (0==cbExpect)
  351.         return POLYLINE_E_UNSUPPORTEDVERSION;
  352.  
  353.     hr=pIStream->Read(&pl, cbExpect, &cb);
  354.  
  355.     if (cbExpect!=cb)
  356.         return POLYLINE_E_READFAILURE;
  357.  
  358.     /*
  359.      * If we loaded successfully, make the data current.  By using
  360.      * DataSet we centralize our version upgrading.  We size the
  361.      * polyline window to the data AND notify the document so it
  362.      * sizes to the polyline.
  363.      */
  364.     DataSet(&pl, TRUE, TRUE);
  365.  
  366.     //Return what version we just loaded.
  367.     return MAKELONG(pl.wVerMin, pl.wVerMaj);
  368.     }
  369.  
  370.  
  371.  
  372.  
  373. /*
  374.  * CPolyline::WriteToStream
  375.  *
  376.  * Purpose:
  377.  *  Ignorantly writes our current data into a stream in a
  378.  *  particular version.
  379.  *
  380.  * Parameters:
  381.  *  pIStream        LPSTREAM in which to save.
  382.  *  lVer            LONG providing version number Major (HI) and
  383.  *                  Minor (Low)
  384.  *
  385.  * Return Value:
  386.  *  LONG            A POLYLINE_E_* value.
  387.  */
  388.  
  389. LONG CPolyline::WriteToStream(LPSTREAM pIStream, LONG lVer)
  390.     {
  391.     ULONG           cb;
  392.     ULONG           cbExpect=0;
  393.     WORD            wVerMaj=HIWORD(lVer);
  394.     WORD            wVerMin=LOWORD(lVer);
  395.     POLYLINEDATA    pl;
  396.     HRESULT         hr;
  397.  
  398.     if (NULL==pIStream)
  399.         return POLYLINE_E_READFAILURE;
  400.  
  401.     //Get a copy of our data in the version we're going to save.
  402.     DataGet(&pl, lVer);
  403.  
  404.     switch (wVerMaj)
  405.         {
  406.         case VERSIONMAJOR:  //2.x
  407.             switch (wVerMin)
  408.                 {
  409.                 case VERSIONMINOR:  //2.0
  410.                     cbExpect=CBPOLYLINEDATA;
  411.                     break;
  412.  
  413.                 default:
  414.                     break;
  415.                 }
  416.             break;
  417.  
  418.         case 1: //1.x
  419.             switch (wVerMin)
  420.                 {
  421.                 case 0:  //1.0
  422.                     cbExpect=CBPOLYLINEDATA10;
  423.                     break;
  424.  
  425.                 default:
  426.                     break;
  427.                 }
  428.             break;
  429.  
  430.         default:
  431.             break;
  432.         }
  433.  
  434.     if (0==cbExpect)
  435.         return POLYLINE_E_UNSUPPORTEDVERSION;
  436.  
  437.     /*
  438.      * If writing to an OLE 1 storage, include the length of
  439.      * data as the first DWORD in the stream.
  440.      */
  441.  
  442.      if (m_fReadFromOLE10 && CBPOLYLINEDATA10==cbExpect)
  443.         {
  444.         hr=pIStream->Write(&cbExpect, sizeof(DWORD), &cb);
  445.  
  446.         if (FAILED(hr) || sizeof(DWORD)!=cb)
  447.             return POLYLINE_E_WRITEFAILURE;
  448.         }
  449.  
  450.     hr=pIStream->Write(&pl, cbExpect, &cb);
  451.  
  452.     if (FAILED(hr) || cbExpect!=cb)
  453.         return POLYLINE_E_WRITEFAILURE;
  454.  
  455.     return POLYLINE_E_NONE;
  456.     }
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464. /*
  465.  * CPolyline::ReadFromFile
  466.  *
  467.  * Purpose:
  468.  *  Loads our data (any known version) from a file handle returning
  469.  *  the version number of the data or an error value.
  470.  *
  471.  * Parameters:
  472.  *  pszFile         LPTSTR of the file to open.
  473.  *
  474.  * Return Value:
  475.  *  LONG            Version number or negative POLYLINE_E_* value.
  476.  */
  477.  
  478. LONG CPolyline::ReadFromFile(LPTSTR pszFile)
  479.     {
  480.     OFSTRUCT        of;
  481.     HFILE           hFile;
  482.     POLYLINEDATA    pl;
  483.     UINT            cb=(UINT)-1;
  484.     UINT            cbExpect=0;
  485.  
  486.     if (NULL==pszFile)
  487.         return POLYLINE_E_READFAILURE;
  488.  
  489.     //OpenFileW is a member of CPolyline.
  490.     hFile=OpenFileW(pszFile, &of, OF_READ);
  491.  
  492.     if (HFILE_ERROR==hFile)
  493.         return POLYLINE_E_READFAILURE;
  494.  
  495.     //Read version numbers and seek back to file beginning.
  496.     cb=_lread(hFile, &pl, 2*sizeof(WORD));
  497.     _llseek(hFile, 0L, 0);
  498.  
  499.     if (2*sizeof(WORD)!=cb)
  500.         {
  501.         _lclose(hFile);
  502.         return POLYLINE_E_READFAILURE;
  503.         }
  504.  
  505.     /*
  506.      * For version 2.0, read the entire file.  For version 1.0 read
  507.      * the file up to CBPOLYLINEDATAVER10.  For anything else, give
  508.      * an error.
  509.      */
  510.  
  511.     switch (pl.wVerMaj)
  512.         {
  513.         case VERSIONMAJOR:  //2.x
  514.             switch (pl.wVerMin)
  515.                 {
  516.                 case VERSIONMINOR:  //2.0
  517.                     cbExpect=CBPOLYLINEDATA;
  518.                     break;
  519.  
  520.                 default:
  521.                     break;
  522.                 }
  523.             break;
  524.  
  525.         case 1: //1.x
  526.             switch (pl.wVerMin)
  527.                 {
  528.                 case 0:  //1.0
  529.                     cbExpect=CBPOLYLINEDATA10;
  530.                     break;
  531.  
  532.                 default:
  533.                     break;
  534.                 }
  535.             break;
  536.  
  537.         default:
  538.             break;
  539.         }
  540.  
  541.     if (0==cbExpect)
  542.         {
  543.         _lclose(hFile);
  544.         return POLYLINE_E_UNSUPPORTEDVERSION;
  545.         }
  546.  
  547.     cb=_lread(hFile, &pl, cbExpect);
  548.     _lclose(hFile);
  549.  
  550.     if (cbExpect!=cb)
  551.         return POLYLINE_E_READFAILURE;
  552.  
  553.     /*
  554.      * If we loaded successfully, make the data current.  By using
  555.      * DataSet we centralize our version upgrading.  We size the
  556.      * polyline window to the data AND notify the document so it
  557.      * sizes to the polyline.
  558.      */
  559.     DataSet(&pl, TRUE, TRUE);
  560.  
  561.     //Return what version we just loaded.
  562.     return MAKELONG(pl.wVerMin, pl.wVerMaj);
  563.     }
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570. /*
  571.  * CPolyline::WriteToFile
  572.  *
  573.  * Purpose:
  574.  *  Ignorantly writes our current data into an opened file in a
  575.  *  particular version.
  576.  *
  577.  * Parameters:
  578.  *  pszFile         LPTSTR filename in which to store the data.
  579.  *  lVer            LONG providing version number Major (HI)
  580.  *                  and Minor (Low)
  581.  *
  582.  * Return Value:
  583.  *  LONG            A POLYLINE_E_* value.
  584.  */
  585.  
  586. LONG CPolyline::WriteToFile(LPTSTR pszFile, LONG lVer)
  587.     {
  588.     OFSTRUCT        of;
  589.     HFILE           hFile;
  590.     UINT            cb;
  591.     UINT            cbExpect=0;
  592.     WORD            wVerMaj=HIWORD(lVer);
  593.     WORD            wVerMin=LOWORD(lVer);
  594.     POLYLINEDATA    pl;
  595.  
  596.     if (NULL==pszFile)
  597.         return POLYLINE_E_READFAILURE;
  598.  
  599.     //Get a copy of our data in the version we're going to save.
  600.     DataGet(&pl, lVer);
  601.  
  602.     switch (wVerMaj)
  603.         {
  604.         case VERSIONMAJOR:  //2.x
  605.             switch (wVerMin)
  606.                 {
  607.                 case VERSIONMINOR:  //2.0
  608.                     cbExpect=CBPOLYLINEDATA;
  609.                     break;
  610.  
  611.                 default:
  612.                     break;
  613.                 }
  614.             break;
  615.  
  616.         case 1: //1.x
  617.             switch (wVerMin)
  618.                 {
  619.                 case 0:  //1.0
  620.                     cbExpect=CBPOLYLINEDATA10;
  621.                     break;
  622.  
  623.                 default:
  624.                     break;
  625.                 }
  626.             break;
  627.  
  628.         default:
  629.             break;
  630.         }
  631.  
  632.     if (0==cbExpect)
  633.         return POLYLINE_E_UNSUPPORTEDVERSION;
  634.  
  635.     hFile=OpenFileW(pszFile, &of, OF_CREATE | OF_WRITE);
  636.  
  637.     if (HFILE_ERROR==hFile)
  638.         return DOCERR_COULDNOTOPEN;
  639.  
  640.     cb=_lwrite(hFile, (LPCSTR)&pl, cbExpect);
  641.     _lclose(hFile);
  642.  
  643.     return (cbExpect==cb) ? POLYLINE_E_NONE
  644.         : POLYLINE_E_WRITEFAILURE;
  645.     }
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652. /*
  653.  * CPolyline::OpenFileW (Private)
  654.  *
  655.  * Purpose:
  656.  *  Under Win32, OpenFile does not take Unicode strings.  This
  657.  *  function converts a Unicode string into an ANSI string and
  658.  *  calls OpenFile.  This just maps to OpenFile without Unicode.
  659.  *
  660.  * Parameters, Return Value:
  661.  *  Same as OpenFile.
  662.  */
  663.  
  664. HFILE CPolyline::OpenFileW(LPTSTR pszFile, LPOFSTRUCT pof
  665.     , UINT uFlags)
  666.     {
  667.    #ifdef UNICODE
  668.     CHAR        szTemp[CCHPATHMAX];
  669.  
  670.     UNICODETOANSI(pszFile, szTemp, CCHPATHMAX);
  671.     return OpenFile(szTemp, pof, uFlags);
  672.    #else
  673.     return OpenFile(pszFile, pof, uFlags);
  674.    #endif
  675.     }
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682.  
  683. /*
  684.  * CPolyline::DataSet
  685.  *
  686.  * Purpose:
  687.  *  Sets the current data in this Polyline to a given structure.
  688.  *
  689.  * Parameters:
  690.  *  ppl             PPOLYLINEDATA to initialize to.
  691.  *  fSizeToData     BOOL indicating if we're to size to the data or
  692.  *                  scale it.
  693.  *  fNotify         BOOL indicating if we're to send an advise on
  694.  *                  this change.
  695.  *
  696.  * Return Value:
  697.  *  LONG            A POLYLINE_E_* value.
  698.  */
  699.  
  700. LONG CPolyline::DataSet(PPOLYLINEDATA ppl, BOOL fSizeToData
  701.     , BOOL fNotify)
  702.     {
  703.     RECTS       rcs;
  704.     RECT        rc;
  705.     UINT        i;
  706.  
  707.     /*
  708.      * Copy the structure in ppl and repaint to reflect the new
  709.      * point set.  Note that unlike the RectSet message, we do no
  710.      * scaling, assuming that the rect in the structure is
  711.      * appropriate for the data.
  712.      */
  713.  
  714.     if (NULL==ppl)
  715.         return POLYLINE_E_INVALIDPOINTER;
  716.  
  717.     //Preserve the old rectangle
  718.     rcs=m_pl.rc;
  719.  
  720.     /*
  721.      * For version 2.0 we perform a straight copy.  For version
  722.      * 1.0 we copy the 1.0 structure and fill in defaults for
  723.      * the 2.0 additions.
  724.      */
  725.  
  726.     switch (ppl->wVerMaj)
  727.         {
  728.         case VERSIONMAJOR:          //2.x
  729.             switch (ppl->wVerMin)
  730.                 {
  731.                 case VERSIONMINOR:  //2.0
  732.                     m_pl=*ppl;
  733.                     break;
  734.  
  735.                 default:
  736.                     return POLYLINE_E_UNSUPPORTEDVERSION;
  737.                 }
  738.             break;
  739.  
  740.         case 1:                     //1.x
  741.             switch (ppl->wVerMin)
  742.                 {
  743.                 case 0:             //1.0
  744.                     *((PPOLYLINEDATA10)&m_pl)=
  745.                         *((PPOLYLINEDATA10)ppl);
  746.  
  747.                     /*
  748.                      * Update this structure to 2.0.  Note that we
  749.                      * assume whoever loaded us to save the loaded
  750.                      * version so it can later ask what version
  751.                      * the user wants to save.
  752.                      */
  753.                     m_pl.wVerMaj=VERSIONMAJOR;
  754.                     m_pl.wVerMin=VERSIONMINOR;
  755.  
  756.                     /*
  757.                      * Version 1.0 stored rc in parent coordinates.
  758.                      * We need those now in our client coodinates.
  759.                      */
  760.                     RECTSTORECT(m_pl.rc, rc);
  761.                     OffsetRect(&rc, -m_pl.rc.left, -m_pl.rc.top);
  762.  
  763.                     /*
  764.                      * 1.0 data had points relative to size of the
  765.                      * rectangle.  We need to scale these to 0-32767
  766.                      * independent of the rectangle for the version
  767.                      * upgrade.
  768.                      */
  769.                     for (i=0; i < m_pl.cPoints; i++)
  770.                         PointScale(&rc, &m_pl.rgpt[i], FALSE);
  771.  
  772.                     RECTTORECTS(rc, m_pl.rc);
  773.  
  774.                     //New 2.0 features
  775.                     m_pl.rgbBackground=GetSysColor(COLOR_WINDOW);
  776.                     m_pl.rgbLine=GetSysColor(COLOR_WINDOWTEXT);
  777.                     m_pl.iLineStyle=PS_SOLID;
  778.                     break;
  779.  
  780.                 default:
  781.                     return POLYLINE_E_UNSUPPORTEDVERSION;
  782.                 }
  783.             break;
  784.  
  785.         default:
  786.             return POLYLINE_E_UNSUPPORTEDVERSION;
  787.         }
  788.  
  789.  
  790.     //Inform our parent of the data change
  791.     if (NULL!=m_pAdv)
  792.         m_pAdv->OnDataChange();
  793.  
  794.     /*
  795.      * If we're scaling the window to fit the data, then use
  796.      * RectSet passing our current rectangle as the new one.
  797.      * That makes sure that the data won't change but that the
  798.      * window is resized.
  799.      */
  800.  
  801.     if (fSizeToData)
  802.         {
  803.         POINT       pt;
  804.  
  805.         /*
  806.          * Get our offset in the parent window so we can RectSet
  807.          * to the right place since RectSet expects rectangle in
  808.          * parent coordinates and we get it in client coordinates.
  809.          */
  810.         GetWindowRect(m_hWnd, &rc);
  811.         pt.x=rc.left;
  812.         pt.y=rc.top;
  813.         ScreenToClient(GetParent(m_hWnd), &pt);
  814.         RECTSTORECT(m_pl.rc, rc);
  815.         OffsetRect(&rc, pt.x, pt.y);
  816.  
  817.         //This will also cause a repaint.
  818.         RectSet(&rc, fNotify);
  819.         }
  820.     else
  821.         {
  822.         //Make sure we're updated.
  823.         InvalidateRect(m_hWnd, NULL, TRUE);
  824.         UpdateWindow(m_hWnd);
  825.         }
  826.  
  827.     return POLYLINE_E_NONE;
  828.     }
  829.  
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836. /*
  837.  * CPolyline::DataGet
  838.  *
  839.  * Purpose:
  840.  *  Retrieves the Polyline's current data.
  841.  *
  842.  * Parameters:
  843.  *  ppl             PPOLYLINEDATA into which we copy the data.
  844.  *  lVer            LONG version of the data to retrieve.  Use
  845.  *                  VERSIONCURRENT to retrieve the most current.
  846.  *
  847.  * Return Value:
  848.  *  LONG            A POLYLINE_E_* value
  849.  */
  850.  
  851. LONG CPolyline::DataGet(PPOLYLINEDATA ppl, LONG lVer)
  852.     {
  853.     UINT        i;
  854.     RECT        rc;
  855.  
  856.     //Retieve the current version
  857.     if (lVer==MAKELONG(VERSIONMINOR, VERSIONMAJOR)
  858.         || VERSIONCURRENT==lVer)
  859.         {
  860.         *ppl=m_pl;
  861.         return POLYLINE_E_NONE;
  862.         }
  863.  
  864.     //Check for versions we support, 1.x
  865.     if (HIWORD(lVer)!=1)
  866.         return POLYLINE_E_UNSUPPORTEDVERSION;
  867.  
  868.     if (LOWORD(lVer)==0)    //Check for 1.0
  869.         {
  870.         //Do 2.0 to 1.0 conversion
  871.         *((PPOLYLINEDATA10)ppl)=*((PPOLYLINEDATA10)&m_pl);
  872.  
  873.         RECTSTORECT(ppl->rc, rc);
  874.  
  875.         //Get the parent coordinates of our rectangle
  876.         if (!IsWindow(m_hWnd))
  877.             OffsetRect(&rc, 8, 8); //This is always the offset.
  878.         else
  879.             RectGet(&rc);
  880.  
  881.         /*
  882.          * 1.0 data has points relative to size of the rectangle.
  883.          * We need to scale these from 0-32767 so we have the
  884.          * right values.
  885.          */
  886.         for (i=0; i < ppl->cPoints; i++)
  887.             PointScale(&rc, &ppl->rgpt[i], TRUE);
  888.  
  889.         RECTTORECTS(rc, ppl->rc);
  890.  
  891.         //Insure old version numbers.
  892.         ppl->wVerMaj=1;
  893.         ppl->wVerMin=0;
  894.  
  895.         ((PPOLYLINEDATA10)ppl)->fDrawEntire=TRUE;
  896.         return POLYLINE_E_NONE;
  897.         }
  898.  
  899.     return POLYLINE_E_UNSUPPORTEDVERSION;
  900.     }
  901.  
  902.  
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909. /*
  910.  * CPolyline::DataSetMem
  911.  *
  912.  * Purpose:
  913.  *  Sets the Polyline's data using a global memory handle
  914.  *  instead of a pointer.
  915.  *
  916.  * Parameters:
  917.  *  hMem            HGLOBAL containing the data.
  918.  *  fFree           BOOL indicating if we're to free the data.
  919.  *                  The memory will be freed regardless of any
  920.  *                  error returned from here.
  921.  *  fSizeToData     BOOL indicating if we're to size to the data
  922.  *                  or scale it.
  923.  *  fNotify         BOOL indicating if we're to send an advise
  924.  *                  on this change.
  925.  *
  926.  * Return Value:
  927.  *  LONG            A POLYLINE_E_* value.
  928.  */
  929.  
  930. LONG CPolyline::DataSetMem(HGLOBAL hMem, BOOL fFree
  931.     , BOOL fSizeToData, BOOL fNotify)
  932.     {
  933.     PPOLYLINEDATA   ppl;
  934.     LONG            lRet=POLYLINE_E_INVALIDPOINTER;
  935.  
  936.     if (NULL!=hMem)
  937.         {
  938.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  939.         lRet=DataSet(ppl, fSizeToData, fNotify);
  940.  
  941.         GlobalUnlock(hMem);
  942.  
  943.         if (fFree)
  944.             GlobalFree(hMem);
  945.         }
  946.  
  947.     return lRet;
  948.     }
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.  
  956. /*
  957.  * CPolyline::DataGetMem
  958.  *
  959.  * Purpose:
  960.  *  Retrieves the Polyline's data in a global memory handle.
  961.  *
  962.  * Parameters:
  963.  *  lVer            LONG version of data to retrieve.
  964.  *  phMem           HGLOBAL * in which to store the handle.
  965.  *
  966.  * Return Value:
  967.  *  LONG            A POLYLINE_E_* value.
  968.  */
  969.  
  970. LONG CPolyline::DataGetMem(LONG lVer, HGLOBAL *phMem)
  971.     {
  972.     HGLOBAL         hMem;
  973.     PPOLYLINEDATA   ppl;
  974.     LONG            lRet;
  975.  
  976.     if (NULL==phMem)
  977.         return POLYLINE_E_INVALIDPOINTER;
  978.  
  979.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  980.         , CBPOLYLINEDATA);
  981.  
  982.     if (NULL!=hMem)
  983.         {
  984.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  985.         lRet=DataGet(ppl, lVer);
  986.         GlobalUnlock(hMem);
  987.  
  988.         if (POLYLINE_E_NONE!=lRet)
  989.             {
  990.             GlobalFree(hMem);
  991.             hMem=NULL;
  992.             }
  993.         }
  994.  
  995.     *phMem=hMem;
  996.     return lRet;
  997.     }
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005. /*
  1006.  * CPolyline::RectGet
  1007.  *
  1008.  * Purpose:
  1009.  *  Returns the rectangle of the Polyline in parent coordinates.
  1010.  *
  1011.  * Parameters:
  1012.  *  pRect           LPRECT in which to return the rectangle.
  1013.  *
  1014.  * Return Value:
  1015.  *  None
  1016.  */
  1017.  
  1018. void CPolyline::RectGet(LPRECT pRect)
  1019.     {
  1020.     RECT        rc;
  1021.     POINT       pt;
  1022.  
  1023.     //Retrieve the size of our rectangle in parent coordinates.
  1024.     GetWindowRect(m_hWnd, &rc);
  1025.     pt.x=rc.left;
  1026.     pt.y=rc.top;
  1027.     ScreenToClient(GetParent(m_hWnd), &pt);
  1028.  
  1029.     SetRect(pRect, pt.x, pt.y, pt.x+(rc.right-rc.left)
  1030.         , pt.y+(rc.bottom-rc.top));
  1031.  
  1032.     return;
  1033.     }
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039. /*
  1040.  * CPolyline::SizeGet
  1041.  *
  1042.  * Purpose:
  1043.  *  Retrieves the size of the Polyline in parent coordinates.
  1044.  *
  1045.  * Parameters:
  1046.  *  pRect           LPRECT in which to return the size.  The right
  1047.  *                  and bottom fields will contain the dimensions.
  1048.  *
  1049.  * Return Value:
  1050.  *  None
  1051.  */
  1052.  
  1053. void CPolyline::SizeGet(LPRECT pRect)
  1054.     {
  1055.     RectGet(pRect);
  1056.     return;
  1057.     }
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064. /*
  1065.  * CPolyline::RectSet
  1066.  *
  1067.  * Purpose:
  1068.  *  Sets a new rectangle for the Polyline which sizes to fit.
  1069.  *
  1070.  * Parameters:
  1071.  *  pRect           LPRECT containing the new rectangle.
  1072.  *  fNotify         BOOL indicating if we're to notify anyone of
  1073.  *                  the change.
  1074.  *
  1075.  * Return Value:
  1076.  *  None
  1077.  */
  1078.  
  1079. void CPolyline::RectSet(LPRECT pRect, BOOL fNotify)
  1080.     {
  1081.     UINT        cx, cy;
  1082.     RECT        rc;
  1083.  
  1084.     //Scale the points from our current size to the new size
  1085.     cx=pRect->right-pRect->left;
  1086.     cy=pRect->bottom-pRect->top;
  1087.  
  1088.     SetWindowPos(m_hWnd, NULL, pRect->left, pRect->top
  1089.         , cx, cy, SWP_NOZORDER);
  1090.  
  1091.     SetRect(&rc, 0, 0, cx, cy);
  1092.     RECTTORECTS(rc, m_pl.rc);
  1093.  
  1094.     if (fNotify && NULL!=m_pAdv)
  1095.         m_pAdv->OnSizeChange();
  1096.  
  1097.     InvalidateRect(m_hWnd, NULL, TRUE);
  1098.  
  1099.     return;
  1100.     }
  1101.  
  1102.  
  1103.  
  1104.  
  1105.  
  1106.  
  1107.  
  1108. /*
  1109.  * CPolyline::SizeSet
  1110.  *
  1111.  * Purpose:
  1112.  *  Sets a new size for the Polyline which sizes to fit.
  1113.  *
  1114.  * Parameters:
  1115.  *  pRect           LPRECT containing the new rectangle.
  1116.  *  fNotify         BOOL indicating if we're to notify anyone of
  1117.  *                  the change.
  1118.  *
  1119.  * Return Value:
  1120.  *  None
  1121.  */
  1122.  
  1123. void CPolyline::SizeSet(LPRECT pRect, BOOL fNotify)
  1124.     {
  1125.     UINT        cx, cy;
  1126.  
  1127.     //Scale the points from our current size to the new size
  1128.     cx=pRect->right-pRect->left;
  1129.     cy=pRect->bottom-pRect->top;
  1130.  
  1131.     SetWindowPos(m_hWnd, NULL, 0, 0, (UINT)cx, (UINT)cy
  1132.         , SWP_NOMOVE | SWP_NOZORDER);
  1133.  
  1134.     if (fNotify && NULL!=m_pAdv)
  1135.         m_pAdv->OnSizeChange();
  1136.  
  1137.     InvalidateRect(m_hWnd, NULL, TRUE);
  1138.  
  1139.     return;
  1140.     }
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147. /*
  1148.  * CPolyline::ColorSet
  1149.  *
  1150.  * Purpose:
  1151.  *  Changes for background or line color in the Polyline
  1152.  *
  1153.  * Parameters:
  1154.  *  iColor          UINT index of the color to change.
  1155.  *  cr              COLORREF new color to use.
  1156.  *
  1157.  * Return Value:
  1158.  *  COLORREF        Previous color for the index iColor.
  1159.  */
  1160.  
  1161. COLORREF CPolyline::ColorSet(UINT iColor, COLORREF cr)
  1162.     {
  1163.     COLORREF    crRet;
  1164.  
  1165.     switch (iColor)
  1166.         {
  1167.         case POLYLINECOLOR_BACKGROUND:
  1168.             crRet=m_pl.rgbBackground;
  1169.             m_pl.rgbBackground=cr;
  1170.             break;
  1171.  
  1172.         case POLYLINECOLOR_LINE:
  1173.             crRet=m_pl.rgbLine;
  1174.             m_pl.rgbLine=cr;
  1175.             break;
  1176.         }
  1177.  
  1178.     //If the color changed, repaint
  1179.     if (crRet!=cr)
  1180.         {
  1181.         if (NULL!=m_pAdv)
  1182.             m_pAdv->OnColorChange();
  1183.  
  1184.         InvalidateRect(m_hWnd, NULL, TRUE);
  1185.         UpdateWindow(m_hWnd);
  1186.         }
  1187.  
  1188.     return crRet;
  1189.     }
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197. /*
  1198.  * CPolyline::ColorGet
  1199.  *
  1200.  * Purpose:
  1201.  *  Retrieves one of the colors currently in use by the Polyline.
  1202.  *
  1203.  * Parameters:
  1204.  *  iColor          UINT identifying the color of interest.
  1205.  *
  1206.  * Return Value:
  1207.  *  COLORREF        Current color for iColor.
  1208.  */
  1209.  
  1210. COLORREF CPolyline::ColorGet(UINT iColor)
  1211.     {
  1212.     COLORREF    crRet;
  1213.  
  1214.     crRet=(POLYLINECOLOR_BACKGROUND==iColor)
  1215.         ? m_pl.rgbBackground : m_pl.rgbLine;
  1216.  
  1217.     return crRet;
  1218.     }
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227. /*
  1228.  * CPolyline::LineStyleSet
  1229.  *
  1230.  * Purpose:
  1231.  *  Changes the line style in use by the Polyline
  1232.  *
  1233.  * Parameters:
  1234.  *  iStyle          UINT style of the line to use.
  1235.  *
  1236.  * Return Value:
  1237.  *  UINT            Previous style.
  1238.  */
  1239.  
  1240. UINT CPolyline::LineStyleSet(UINT iStyle)
  1241.     {
  1242.     UINT        uRet=(UINT)m_pl.iLineStyle;
  1243.  
  1244.     //Validate the line style
  1245.     if (PS_SOLID==iStyle || PS_DASH==iStyle || PS_DOT==iStyle
  1246.         || PS_DASHDOT==iStyle || PS_DASHDOTDOT==iStyle)
  1247.         {
  1248.         m_pl.iLineStyle=iStyle;
  1249.  
  1250.         if (uRet!=(UINT)m_pl.iLineStyle)
  1251.             {
  1252.             if (NULL!=m_pAdv)
  1253.                 m_pAdv->OnLineStyleChange();
  1254.  
  1255.             InvalidateRect(m_hWnd, NULL, TRUE);
  1256.             UpdateWindow(m_hWnd);
  1257.             }
  1258.         }
  1259.  
  1260.     return uRet;
  1261.     }
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269. /*
  1270.  * CPolyline::LineStyleGet
  1271.  *
  1272.  * Purpose:
  1273.  *  Retrieves the current line style in use in the Polyline
  1274.  *
  1275.  * Parameters:
  1276.  *  None
  1277.  *
  1278.  * Return Value:
  1279.  *  UINT            Current line style.
  1280.  */
  1281.  
  1282. UINT CPolyline::LineStyleGet(void)
  1283.     {
  1284.     return m_pl.iLineStyle;
  1285.     }
  1286.  
  1287.  
  1288.  
  1289.  
  1290.  
  1291.  
  1292. /*
  1293.  * CPolyline::RenderBitmap
  1294.  *
  1295.  * Purpose:
  1296.  *  Creates a bitmap image of the current Polyline.
  1297.  *
  1298.  * Parameters:
  1299.  *  None
  1300.  *
  1301.  * Return Value:
  1302.  *  HBITMAP         Handle to the newly rendered bitmap.
  1303.  */
  1304.  
  1305. HBITMAP CPolyline::RenderBitmap(void)
  1306.     {
  1307.     HDC         hDC;
  1308.     HDC         hMemDC;
  1309.     HBITMAP     hBmp;
  1310.     RECT        rc;
  1311.     HGDIOBJ     hObj;
  1312.  
  1313.     //Render a bitmap the size of the current rectangle.
  1314.     hDC=GetDC(m_hWnd);
  1315.     hMemDC=CreateCompatibleDC(hDC);
  1316.  
  1317.     GetClientRect(m_hWnd, &rc);
  1318.     hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  1319.  
  1320.     if (NULL!=hBmp)
  1321.         {
  1322.         //Draw the POLYLINEDATA into the bitmap.
  1323.         hObj=SelectObject(hMemDC, hBmp);
  1324.         Draw(hMemDC, FALSE, TRUE);
  1325.         SelectObject(hMemDC, hObj);
  1326.         }
  1327.  
  1328.     DeleteDC(hMemDC);
  1329.     ReleaseDC(m_hWnd, hDC);
  1330.  
  1331.     return hBmp;
  1332.     }
  1333.  
  1334.  
  1335.  
  1336.  
  1337.  
  1338.  
  1339.  
  1340. /*
  1341.  * CPolyline::RenderMetafile
  1342.  *
  1343.  * Purpose:
  1344.  *  Renders the current image of the Polyline into a metafile.
  1345.  *
  1346.  * Parameters:
  1347.  *  None
  1348.  *
  1349.  * Return Value:
  1350.  *  HMETAFILE       Handle to the newly created metafile.
  1351.  */
  1352.  
  1353. HMETAFILE CPolyline::RenderMetafile(void)
  1354.     {
  1355.     HDC         hDC;
  1356.     HMETAFILE   hMF;
  1357.     RECT        rc;
  1358.  
  1359.     //Create a memory metafile and return its handle.
  1360.     hDC=(HDC)CreateMetaFile(NULL);
  1361.     hMF=NULL;
  1362.  
  1363.     if (NULL!=hDC)
  1364.         {
  1365.         /*
  1366.          * This is absolutely essential to the metafile so it
  1367.          * can be scaled in the clipboard and any destination
  1368.          * application.
  1369.          */
  1370.         SetMapMode(hDC, MM_ANISOTROPIC);
  1371.         GetClientRect(m_hWnd, &rc);
  1372.         SetWindowOrgEx(hDC, 0, 0, NULL);
  1373.         SetWindowExtEx(hDC, rc.right, rc.bottom, NULL);
  1374.  
  1375.         Draw(hDC, TRUE, TRUE);
  1376.         hMF=CloseMetaFile(hDC);
  1377.         }
  1378.  
  1379.     return hMF;
  1380.     }
  1381.  
  1382.  
  1383.  
  1384.  
  1385.  
  1386.  
  1387. /*
  1388.  * CPolyline::RenderMetafilePict
  1389.  *
  1390.  * Purpose:
  1391.  *  Renders the current Polyline into a METAFILEPICT structure in
  1392.  *  global memory.
  1393.  *
  1394.  * Parameters:
  1395.  *  None
  1396.  *
  1397.  * Return Value:
  1398.  *  HGLOBAL         Memory containing the METAFILEPICT structure.
  1399.  */
  1400.  
  1401. HGLOBAL CPolyline::RenderMetafilePict(void)
  1402.     {
  1403.     HGLOBAL         hMem;
  1404.     HMETAFILE       hMF;
  1405.     LPMETAFILEPICT  pMF;
  1406.     RECT            rc;
  1407.  
  1408.  
  1409.     //Get the metafile
  1410.     hMF=RenderMetafile();
  1411.  
  1412.     if (NULL==hMF)
  1413.         return NULL;
  1414.  
  1415.     //Allocate the METAFILEPICT structure.
  1416.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  1417.         , sizeof(METAFILEPICT));
  1418.  
  1419.     if (NULL==hMem)
  1420.         {
  1421.         DeleteMetaFile(hMF);
  1422.         return NULL;
  1423.         }
  1424.  
  1425.     /*
  1426.      * Global lock only fails in PMODE if the selector is invalid
  1427.      * (like it was discarded) or references a 0 length segment,
  1428.      * neither of which can happen here.
  1429.      */
  1430.     pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  1431.  
  1432.     pMF->hMF=hMF;
  1433.     pMF->mm=MM_ANISOTROPIC;
  1434.  
  1435.     //Insert the extents in MM_HIMETRIC units.
  1436.     GetClientRect(m_hWnd, &rc);
  1437.     RectConvertMappings(&rc, FALSE);
  1438.     pMF->xExt=rc.right;
  1439.     pMF->yExt=rc.bottom;
  1440.  
  1441.     GlobalUnlock(hMem);
  1442.     return hMem;
  1443.     }
  1444.  
  1445.  
  1446.  
  1447.  
  1448.  
  1449.  
  1450. /*
  1451.  * CPolyline::RectConvertMappings
  1452.  *
  1453.  * Purpose:
  1454.  *  Converts the contents of a rectangle from device (MM_TEXT) or
  1455.  *  HIMETRIC to the other.
  1456.  *
  1457.  * Parameters:
  1458.  *  pRect           LPRECT containing the rectangle to convert.
  1459.  *  fToDevice       BOOL TRUE to convert from HIMETRIC to device,
  1460.  *                  FALSE to convert device to HIMETRIC.
  1461.  *
  1462.  * Return Value:
  1463.  *  None
  1464.  */
  1465.  
  1466. void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
  1467.     {
  1468.     HDC      hDC;
  1469.     int      iLpx, iLpy;
  1470.  
  1471.     if (NULL==pRect)
  1472.         return;
  1473.  
  1474.     hDC=GetDC(NULL);
  1475.     iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
  1476.     iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
  1477.     ReleaseDC(NULL, hDC);
  1478.  
  1479.     if (fToDevice)
  1480.         {
  1481.         pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
  1482.         pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);
  1483.  
  1484.         pRect->right=MulDiv(iLpx, pRect->right,  HIMETRIC_PER_INCH);
  1485.         pRect->bottom=MulDiv(iLpy, pRect->bottom,HIMETRIC_PER_INCH);
  1486.  
  1487.        #ifdef NEVER
  1488.         /*
  1489.          * In this conversion we may get situations where the top
  1490.          * coordinate is larger than the bottom, which messes us up.
  1491.          */
  1492.         if (pRect->bottom < pRect->top)
  1493.             {
  1494.             iLpy=pRect->top;
  1495.             pRect->top=pRect->bottom;
  1496.             pRect->bottom=iLpy;
  1497.             }
  1498.        #endif
  1499.         }
  1500.     else
  1501.         {
  1502.         pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
  1503.         pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);
  1504.  
  1505.         pRect->right =MulDiv(pRect->right, HIMETRIC_PER_INCH, iLpx);
  1506.         pRect->bottom=MulDiv(pRect->bottom,HIMETRIC_PER_INCH, iLpy);
  1507.         }
  1508.  
  1509.     return;
  1510.     }
  1511.