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 / chap18 / cosmo / polyline.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  34KB  |  1,523 lines

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