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 / chap19 / polyline / polyline.cpp < prev    next >
C/C++ Source or Header  |  1996-05-21  |  20KB  |  858 lines

  1. /*
  2.  * POLYLINE.CPP
  3.  * Polyline Component Chapter 19
  4.  *
  5.  * Implementation of the CPolyline class that we expose as a
  6.  * component 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.  * CPolyline:CPolyline
  21.  * CPolyline::~CPolyline
  22.  *
  23.  * Constructor Parameters:
  24.  *  pUnkOuter       LPUNKNOWN of the controlling unknown.
  25.  *  pfnDestroy      PFNDESTROYED to call when an object is
  26.  *                  destroyed.
  27.  *  hInst           HINSTANCE of the application we're in.
  28.  */
  29.  
  30. CPolyline::CPolyline(LPUNKNOWN pUnkOuter, PFNDESTROYED pfnDestroy
  31.     , HINSTANCE hInst)
  32.     {
  33.     m_hWnd=NULL;
  34.     m_hInst=hInst;
  35.  
  36.     m_cRef=0;
  37.     m_pUnkOuter=pUnkOuter;
  38.     m_pfnDestroy=pfnDestroy;
  39.     m_fDirty=FALSE;
  40.  
  41.     m_pImpIPolyline=NULL;
  42.     m_pImpIConnPtCont=NULL;
  43.  
  44.     m_pAdv=NULL;
  45.     m_pConnPt=NULL;
  46.  
  47.     m_pST  =NULL;
  48.     m_cf   =0;
  49.     //CHAPTER19MOD
  50.     m_clsID=CLSID_Polyline19;
  51.     //End CHAPTER19MOD
  52.  
  53.     m_pIStorage=NULL;
  54.     m_pIStream =NULL;
  55.  
  56.     m_pImpIPersistStorage=NULL;
  57.     m_pImpIPersistStreamInit=NULL;
  58.  
  59.     m_pImpIDataObject   =NULL;
  60.     m_pIDataAdviseHolder=NULL;
  61.  
  62.     //CHAPTER19MOD
  63.     m_pDefIUnknown       =NULL;
  64.     m_pDefIDataObject    =NULL;
  65.     m_pDefIViewObject    =NULL;
  66.     m_pDefIPersistStorage=NULL;
  67.  
  68.     m_pIOleAdviseHolder =NULL;
  69.     m_pImpIOleObject    =NULL;
  70.     m_pIOleClientSite   =NULL;
  71.     m_pImpIViewObject   =NULL;
  72.     m_pIAdviseSink      =NULL;
  73.  
  74.     m_dwFrozenAspects   =0;
  75.     m_dwAdviseAspects   =0;
  76.     m_dwAdviseFlags     =0;
  77.  
  78.     m_pImpIRunnableObject=NULL;
  79.     m_hDlg=NULL;
  80.     //End CHAPTER19MOD
  81.  
  82.     return;
  83.     }
  84.  
  85.  
  86. CPolyline::~CPolyline(void)
  87.     {
  88.     //CHAPTER19MOD
  89.     LPUNKNOWN       pIUnknown=this;
  90.  
  91.     if (NULL!=m_pUnkOuter)
  92.         pIUnknown=m_pUnkOuter;
  93.     //End CHAPTER19MOD
  94.  
  95.     if (NULL!=m_pST)
  96.         delete m_pST;
  97.  
  98.     //CHAPTER19MOD
  99.     if (NULL!=m_hDlg)
  100.         DestroyWindow(m_hDlg);
  101.  
  102.     /*
  103.      * In aggregation, release cached pointers but
  104.      * AddRef the controlling unknown first.  The
  105.      * extra reference count protects us from reentrancy.
  106.      */
  107.  
  108.     m_cRef++;
  109.  
  110.     pIUnknown->AddRef();
  111.     pIUnknown->AddRef();
  112.     pIUnknown->AddRef();
  113.  
  114.     ReleaseInterface(m_pDefIViewObject);
  115.     ReleaseInterface(m_pDefIDataObject);
  116.     ReleaseInterface(m_pDefIPersistStorage);
  117.  
  118.     m_cRef--;
  119.  
  120.     //Cached pointer rules do not apply to IUnknown
  121.     ReleaseInterface(m_pDefIUnknown);
  122.  
  123.     ReleaseInterface(m_pIAdviseSink);
  124.     ReleaseInterface(m_pIOleClientSite);
  125.     ReleaseInterface(m_pIOleAdviseHolder);
  126.  
  127.     DeleteInterfaceImp(m_pImpIOleObject);
  128.     DeleteInterfaceImp(m_pImpIViewObject);
  129.     DeleteInterfaceImp(m_pImpIRunnableObject);
  130.     //End CHAPTER19MOD
  131.  
  132.     ReleaseInterface(m_pIDataAdviseHolder);
  133.     DeleteInterfaceImp(m_pImpIDataObject);
  134.  
  135.     DeleteInterfaceImp(m_pImpIPersistStreamInit);
  136.     DeleteInterfaceImp(m_pImpIPersistStorage);
  137.     ReleaseInterface(m_pIStream);
  138.     ReleaseInterface(m_pIStorage);
  139.  
  140.     DeleteInterfaceImp(m_pImpIConnPtCont);
  141.     DeleteInterfaceImp(m_pImpIPolyline);
  142.  
  143.     ReleaseInterface(m_pAdv);
  144.     ReleaseInterface(m_pConnPt);
  145.  
  146.     return;
  147.     }
  148.  
  149.  
  150.  
  151.  
  152. /*
  153.  * CPolyline::Init
  154.  *
  155.  * Purpose:
  156.  *  Performs any intiailization of a CPolyline that's prone to
  157.  *  failure that we also use internally before exposing the
  158.  *  object outside this DLL.
  159.  *
  160.  * Parameters:
  161.  *  None
  162.  *
  163.  * Return Value:
  164.  *  BOOL            TRUE if the function is successful,
  165.  *                  FALSE otherwise.
  166.  */
  167.  
  168. BOOL CPolyline::Init(void)
  169.     {
  170.     LPUNKNOWN       pIUnknown=this;
  171.     //CHAPTER19MOD
  172.     HRESULT         hr;
  173.     //End CHAPTER19MOD
  174.  
  175.     if (NULL!=m_pUnkOuter)
  176.         pIUnknown=m_pUnkOuter;
  177.  
  178.     m_pST=new CStringTable(m_hInst);
  179.  
  180.     if (!m_pST->Init(IDS_POLYLINEMIN, IDS_POLYLINEMAX))
  181.         return FALSE;
  182.  
  183.     m_cf=RegisterClipboardFormat(SZPOLYLINECLIPFORMAT);
  184.  
  185.     m_pImpIPersistStorage=new CImpIPersistStorage(this, pIUnknown);
  186.  
  187.     if (NULL==m_pImpIPersistStorage)
  188.         return FALSE;
  189.  
  190.     m_pImpIPersistStreamInit=new CImpIPersistStreamInit(this
  191.         , pIUnknown);
  192.  
  193.     if (NULL==m_pImpIPersistStreamInit)
  194.         return FALSE;
  195.  
  196.     m_pImpIPolyline=new CImpIPolyline(this, pIUnknown);
  197.  
  198.     if (NULL==m_pImpIPolyline)
  199.         return FALSE;
  200.  
  201.     m_pImpIConnPtCont=new CImpIConnPtCont(this, pIUnknown);
  202.  
  203.     if (NULL==m_pImpIConnPtCont)
  204.         return FALSE;
  205.  
  206.     m_pConnPt=new CConnectionPoint(this);
  207.  
  208.     if (NULL==m_pConnPt)
  209.         return FALSE;
  210.  
  211.     m_pConnPt->AddRef();    //Reversed in destructor
  212.  
  213.     m_pImpIDataObject=new CImpIDataObject(this, pIUnknown);
  214.  
  215.     if (NULL==m_pImpIDataObject)
  216.         return FALSE;
  217.  
  218.     //CHAPTER19MOD
  219.     //FORMATETC arrays not needed:  using Def Handler
  220.  
  221.     m_pImpIOleObject=new CImpIOleObject(this, pIUnknown);
  222.  
  223.     if (NULL==m_pImpIOleObject)
  224.         return FALSE;
  225.  
  226.     m_pImpIViewObject=new CImpIViewObject(this, pIUnknown);
  227.  
  228.     if (NULL==m_pImpIViewObject)
  229.         return FALSE;
  230.  
  231.     m_pImpIRunnableObject=new CImpIRunnableObject(this, pIUnknown);
  232.  
  233.     if (NULL==m_pImpIRunnableObject)
  234.         return FALSE;
  235.  
  236.     /*
  237.      * We're sitting at ref count 0 and the next call will AddRef a
  238.      * few times and Release a few times.  This insures we don't
  239.      * delete ourselves prematurely.
  240.      */
  241.     m_cRef++;
  242.  
  243.     //Aggregate OLE's cache for IOleCache* interfaces.
  244.     hr=CreateDataCache(pIUnknown, CLSID_Polyline19
  245.         , IID_IUnknown, (PPVOID)&m_pDefIUnknown);
  246.  
  247.     if (FAILED(hr))
  248.         return FALSE;
  249.  
  250.     /*
  251.      * NOTE:  The spec specifically states that any interfaces
  252.      * besides IUnknown that we obtain on an aggregated object
  253.      * should be Released immediately after we QueryInterface for
  254.      * them because the QueryInterface will AddRef us, and since
  255.      * we would not release these interfaces until we were
  256.      * destroyed, we'd never go away because we'd never get a zero
  257.      * ref count.
  258.      */
  259.  
  260.     //Now try to get other interfaces to which we delegate
  261.     hr=m_pDefIUnknown->QueryInterface(IID_IViewObject2
  262.         , (PPVOID)&m_pDefIViewObject);
  263.  
  264.     if (FAILED(hr))
  265.         return FALSE;
  266.  
  267.     pIUnknown->Release();
  268.  
  269.     hr=m_pDefIUnknown->QueryInterface(IID_IDataObject
  270.         , (PPVOID)&m_pDefIDataObject);
  271.  
  272.     if (FAILED(hr))
  273.         return FALSE;
  274.  
  275.     pIUnknown->Release();
  276.  
  277.     hr=m_pDefIUnknown->QueryInterface(IID_IPersistStorage
  278.         , (PPVOID)&m_pDefIPersistStorage);
  279.  
  280.     if (FAILED(hr))
  281.         return FALSE;
  282.  
  283.     pIUnknown->Release();
  284.  
  285.     m_cRef--;
  286.     m_pImpIPolyline->New();
  287.     //End CHAPTER19MOD
  288.  
  289.     return TRUE;
  290.     }
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298. /*
  299.  * CPolyline::QueryInterface
  300.  * CPolyline::AddRef
  301.  * CPolyline::Release
  302.  *
  303.  * Purpose:
  304.  *  IUnknown members for CPolyline object.
  305.  */
  306.  
  307. STDMETHODIMP CPolyline::QueryInterface(REFIID riid, PPVOID ppv)
  308.     {
  309.     *ppv=NULL;
  310.  
  311.     if (IID_IUnknown==riid)
  312.         *ppv=this;
  313.  
  314.     if (IID_IConnectionPointContainer==riid)
  315.         *ppv=m_pImpIConnPtCont;
  316.  
  317.     if (IID_IPolyline10==riid)
  318.         *ppv=m_pImpIPolyline;
  319.  
  320.     if (IID_IPersistStorage==riid)
  321.         *ppv=m_pImpIPersistStorage;
  322.  
  323.     if (IID_IPersist==riid || IID_IPersistStream==riid
  324.         || IID_IPersistStreamInit==riid)
  325.         *ppv=m_pImpIPersistStreamInit;
  326.  
  327.     if (IID_IDataObject==riid)
  328.         *ppv=m_pImpIDataObject;
  329.  
  330.     //CHAPTER19MOD
  331.     if (IID_IOleObject==riid)
  332.         *ppv=m_pImpIOleObject;
  333.  
  334.     if (IID_IViewObject==riid || IID_IViewObject2==riid)
  335.         *ppv=m_pImpIViewObject;
  336.  
  337.     if (IID_IRunnableObject==riid)
  338.         *ppv=m_pImpIRunnableObject;
  339.  
  340.     //Use the default handler's cache.
  341.     if (IID_IOleCache==riid || IID_IOleCache2==riid)
  342.         return m_pDefIUnknown->QueryInterface(riid, ppv);
  343.     //End CHAPTER19MOD
  344.  
  345.     if (NULL!=*ppv)
  346.         {
  347.         ((LPUNKNOWN)*ppv)->AddRef();
  348.         return NOERROR;
  349.         }
  350.  
  351.     return ResultFromScode(E_NOINTERFACE);
  352.     }
  353.  
  354.  
  355. STDMETHODIMP_(ULONG) CPolyline::AddRef(void)
  356.     {
  357.     return ++m_cRef;
  358.     }
  359.  
  360.  
  361. STDMETHODIMP_(ULONG) CPolyline::Release(void)
  362.     {
  363.     if (0L!=--m_cRef)
  364.         return m_cRef;
  365.  
  366.     if (NULL!=m_pfnDestroy)
  367.         (*m_pfnDestroy)();
  368.  
  369.     delete this;
  370.     return 0L;
  371.     }
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379. /*
  380.  * CPolyline::RectConvertMappings
  381.  *
  382.  * Purpose:
  383.  *  Converts the contents of a rectangle from device (MM_TEXT) or
  384.  *  HIMETRIC to the other.
  385.  *
  386.  * Parameters:
  387.  *  pRect           LPRECT containing the rectangle to convert.
  388.  *  fToDevice       BOOL TRUE to convert from HIMETRIC to device,
  389.  *                  FALSE to convert device to HIMETRIC.
  390.  *
  391.  * Return Value:
  392.  *  None
  393.  */
  394.  
  395. void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
  396.     {
  397.     HDC      hDC;
  398.     int      iLpx, iLpy;
  399.  
  400.     if (NULL==pRect)
  401.         return;
  402.  
  403.     hDC=GetDC(NULL);
  404.     iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
  405.     iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
  406.     ReleaseDC(NULL, hDC);
  407.  
  408.     if (fToDevice)
  409.         {
  410.         pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
  411.         pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);
  412.  
  413.         pRect->right =MulDiv(iLpx, pRect->right, HIMETRIC_PER_INCH);
  414.         pRect->bottom=MulDiv(iLpy, pRect->bottom,HIMETRIC_PER_INCH);
  415.         }
  416.     else
  417.         {
  418.         pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
  419.         pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);
  420.  
  421.         pRect->right =MulDiv(pRect->right, HIMETRIC_PER_INCH, iLpx);
  422.         pRect->bottom=MulDiv(pRect->bottom,HIMETRIC_PER_INCH, iLpy);
  423.         }
  424.  
  425.     return;
  426.     }
  427.  
  428.  
  429.  
  430. /*
  431.  * CPolyline::DataSet
  432.  *
  433.  * Purpose:
  434.  *  Sets the current data in this Polyline to a given structure.
  435.  *
  436.  * Parameters:
  437.  *  pplIn           PPOLYLINEDATA to initialize to.
  438.  *  fSizeToData     BOOL indicating if we're to size to the data
  439.  *                  or scale it.
  440.  *  fNotify         BOOL indicating if we're to send an advise
  441.  *                  on this change.
  442.  *
  443.  * Return Value:
  444.  *  HRESULT         NOERROR if successful, otherwise a
  445.  *                  POLYLINE_E_ value.
  446.  */
  447.  
  448. STDMETHODIMP CPolyline::DataSet(PPOLYLINEDATA pplIn
  449.     , BOOL fSizeToData, BOOL fNotify)
  450.     {
  451.     RECT            rc;
  452.  
  453.     /*
  454.      * Copy the structure in pplIn and repaint to reflect the
  455.      * new point set.  Note that unlike the RectSet message, we
  456.      * do no scaling, assuming that the rect in the structure
  457.      * is appropriate for the data.
  458.      */
  459.  
  460.     if (NULL==pplIn)
  461.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  462.  
  463.     m_pl=*pplIn;
  464.     m_fDirty=TRUE;
  465.  
  466.     //CHAPTER19MOD
  467.     //Calling OnDataChange happens below through SendAdvise.
  468.     //End CHAPTER19MOD
  469.  
  470.     /*
  471.      * If we're scaling the window to fit the data, then use
  472.      * RectSet passing our current rectangle as the new one.
  473.      * That makes sure that the data won't change but that the
  474.      * window is resized.
  475.      */
  476.  
  477.     if (fSizeToData)
  478.         {
  479.         POINT       pt;
  480.  
  481.         /*
  482.          * Get our offset in the parent window so we can RectSet
  483.          * to the right place since RectSet expects rectangle in
  484.          * parent coordinates and we get it in client coordinates.
  485.          */
  486.         if (NULL!=m_hWnd)
  487.             {
  488.             GetWindowRect(m_hWnd, &rc);
  489.             pt.x=rc.left;
  490.             pt.y=rc.top;
  491.             ScreenToClient(GetParent(m_hWnd), &pt);
  492.             RECTSTORECT(m_pl.rc, rc);
  493.             OffsetRect(&rc, pt.x, pt.y);
  494.  
  495.             //This will also cause a repaint.
  496.             m_pImpIPolyline->RectSet(&rc, fNotify);
  497.             }
  498.         }
  499.     else
  500.         {
  501.         if (NULL!=m_hWnd)
  502.             {
  503.             //Make sure we're updated.
  504.             InvalidateRect(m_hWnd, NULL, TRUE);
  505.             UpdateWindow(m_hWnd);
  506.             }
  507.         }
  508.  
  509.     //CHAPTER19MOD
  510.     SendAdvise(OBJECTCODE_DATACHANGED);
  511.     //End CHAPTER19MOD
  512.  
  513.     return NOERROR;
  514.     }
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522. /*
  523.  * CPolyline::DataGet
  524.  *
  525.  * Purpose:
  526.  *  Retrieves the Polyline's current data.
  527.  *
  528.  * Parameters:
  529.  *  pplIn           PPOLYLINEDATA into which we copy the data.
  530.  *
  531.  * Return Value:
  532.  *  HRESULT         NOERROR if successful, otherwise a
  533.  *                  POLYLINE_E_ value.
  534.  */
  535.  
  536. STDMETHODIMP CPolyline::DataGet(PPOLYLINEDATA pplIn)
  537.     {
  538.     if (NULL==pplIn)
  539.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  540.  
  541.     *pplIn=m_pl;
  542.     return NOERROR;
  543.     }
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550. /*
  551.  * CPolyline::RenderNative
  552.  *
  553.  * Purpose:
  554.  *  Retrieves the Polyline's data in a global memory handle.
  555.  *
  556.  * Parameters:
  557.  *  phMem           HGLOBAL * in which to store the handle.
  558.  *
  559.  * Return Value:
  560.  *  HRESULT         NOERROR if successful, otherwise a
  561.  *                  POLYLINE_E_ value.
  562.  */
  563.  
  564. STDMETHODIMP CPolyline::RenderNative(HGLOBAL *phMem)
  565.     {
  566.     HGLOBAL         hMem;
  567.     PPOLYLINEDATA   ppl;
  568.     HRESULT         hr=ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  569.  
  570.     if (NULL==phMem)
  571.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  572.  
  573.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, CBPOLYLINEDATA);
  574.  
  575.     if (NULL!=hMem)
  576.         {
  577.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  578.         hr=DataGet(ppl);
  579.  
  580.         GlobalUnlock(hMem);
  581.  
  582.         if (FAILED(hr))
  583.             {
  584.             GlobalFree(hMem);
  585.             hMem=NULL;
  586.             }
  587.         }
  588.  
  589.     *phMem=hMem;
  590.     return hr;
  591.     }
  592.  
  593.  
  594.  
  595.  
  596. /*
  597.  * CPolyline::RenderBitmap
  598.  *
  599.  * Purpose:
  600.  *  Creates a bitmap image of the current Polyline.
  601.  *
  602.  * Parameters:
  603.  *  phBmp           HBITMAP * in which to return the bitmap.
  604.  *
  605.  * Return Value:
  606.  *  HRESULT         NOERROR if successful, otherwise a
  607.  *                  POLYLINE_E_ value.
  608.  */
  609.  
  610. STDMETHODIMP CPolyline::RenderBitmap(HBITMAP *phBmp)
  611.     {
  612.     HDC             hDC;
  613.     HDC             hMemDC;
  614.     HBITMAP         hBmp;
  615.     RECT            rc;
  616.     HGDIOBJ         hObj;
  617.  
  618.     if (NULL==phBmp)
  619.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  620.  
  621.     //Render a bitmap the size of the current rectangle.
  622.     hDC=GetDC(m_hWnd);
  623.     hMemDC=CreateCompatibleDC(hDC);
  624.  
  625.     GetClientRect(m_hWnd, &rc);
  626.     hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  627.  
  628.     if (NULL!=hBmp)
  629.         {
  630.         //Draw the POLYLINEDATA into the bitmap.
  631.         hObj=SelectObject(hMemDC, hBmp);
  632.         //CHAPTER19MOD
  633.         Draw(hMemDC, FALSE, TRUE, &rc, NULL);
  634.         //End CHAPTER19MOD
  635.         SelectObject(hMemDC, hObj);
  636.         }
  637.  
  638.     DeleteDC(hMemDC);
  639.     ReleaseDC(m_hWnd, hDC);
  640.  
  641.     *phBmp=hBmp;
  642.     return NOERROR;
  643.     }
  644.  
  645.  
  646.  
  647. //RenderMetafile not necessary--now part of RenderMetafilePict.
  648.  
  649.  
  650.  
  651. /*
  652.  * CPolyline::RenderMetafilePict
  653.  *
  654.  * Purpose:
  655.  *  Renders the current Polyline into a METAFILEPICT structure in
  656.  *  global memory.
  657.  *
  658.  * Parameters:
  659.  *  phMem           HGLOBAL * in which to return the
  660.  *                  METAFILEPICT.
  661.  *
  662.  * Return Value:
  663.  *  HRESULT         NOERROR if successful, otherwise a
  664.  *                  POLYLINE_E_ value.
  665.  */
  666.  
  667. STDMETHODIMP CPolyline::RenderMetafilePict(HGLOBAL *phMem)
  668.     {
  669.     HGLOBAL         hMem;
  670.     HMETAFILE       hMF;
  671.     LPMETAFILEPICT  pMF;
  672.     RECT            rc;
  673.     HDC             hDC;
  674.  
  675.     if (NULL==phMem)
  676.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  677.  
  678.     //Create a memory metafile and return its handle.
  679.     hDC=(HDC)CreateMetaFile(NULL);
  680.  
  681.     if (NULL==hDC)
  682.         return ResultFromScode(STG_E_MEDIUMFULL);
  683.  
  684.     SetMapMode(hDC, MM_ANISOTROPIC);
  685.     GetClientRect(m_hWnd, &rc);
  686.     SetWindowOrgEx(hDC, 0, 0, NULL);
  687.     SetWindowExtEx(hDC, rc.right, rc.bottom, NULL);
  688.  
  689.     //CHAPTER19MOD
  690.     Draw(hDC, TRUE, TRUE, &rc, NULL);
  691.     //End CHAPTER19MOD
  692.     hMF=CloseMetaFile(hDC);
  693.  
  694.     if (NULL==hMF)
  695.         return ResultFromScode(STG_E_MEDIUMFULL);
  696.  
  697.     //Allocate the METAFILEPICT structure.
  698.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  699.         , sizeof(METAFILEPICT));
  700.  
  701.     if (NULL==hMem)
  702.         {
  703.         DeleteMetaFile(hMF);
  704.         return ResultFromScode(E_FAIL);
  705.         }
  706.  
  707.     /*
  708.      * Global lock only fails in PMODE if the selector is invalid
  709.      * (like it was discarded) or references a 0 length segment,
  710.      * neither of which can happen here.
  711.      */
  712.     pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  713.  
  714.     pMF->hMF=hMF;
  715.     pMF->mm=MM_ANISOTROPIC;
  716.  
  717.     //Insert the extents in MM_HIMETRIC units.
  718.     GetClientRect(m_hWnd, &rc);
  719.     RectConvertMappings(&rc, FALSE);
  720.     pMF->xExt=rc.right;
  721.     pMF->yExt=rc.bottom;
  722.  
  723.     GlobalUnlock(hMem);
  724.  
  725.     *phMem=hMem;
  726.     return NOERROR;
  727.     }
  728.  
  729.  
  730.  
  731. //CHAPTER19MOD
  732. /*
  733.  * CPolyline::Instance
  734.  *
  735.  * Purpose:
  736.  *  Provides access to the module instance.
  737.  *
  738.  * Parameters:
  739.  *  None
  740.  *
  741.  * Return Value:
  742.  *  HINSTANCE       The instance handle of the module.
  743.  */
  744.  
  745. HINSTANCE CPolyline::Instance(void)
  746.     {
  747.     return m_hInst;
  748.     }
  749.  
  750.  
  751.  
  752. /*
  753.  * CPolyline::String
  754.  *
  755.  * Purpose:
  756.  *  Provides string lookup in the Polyline string table.
  757.  *
  758.  * Parameters:
  759.  *  uID             UINT of the string to return.
  760.  *
  761.  * Return Value:
  762.  *  LPTSTR          Pointer to the string.
  763.  */
  764.  
  765. LPTSTR CPolyline::String(UINT uID)
  766.     {
  767.     return PSZ(uID);
  768.     }
  769.  
  770.  
  771.  
  772.  
  773. /*
  774.  * CPolyline::SendAdvise
  775.  *
  776.  * Purpose:
  777.  *  Calls the appropriate IOleClientSite or IAdviseSink member
  778.  *  function for various events such as closure, renaming, etc.
  779.  *
  780.  * Parameters:
  781.  *  uCode           UINT OBJECTCODE_* identifying the notification.
  782.  *
  783.  * Return Value:
  784.  *  None
  785.  */
  786.  
  787. void CPolyline::SendAdvise(UINT uCode)
  788.     {
  789.     DWORD       dwAspect=DVASPECT_CONTENT | DVASPECT_THUMBNAIL;
  790.  
  791.     switch (uCode)
  792.         {
  793.         case OBJECTCODE_SAVED:
  794.             if (NULL!=m_pIOleAdviseHolder)
  795.                 m_pIOleAdviseHolder->SendOnSave();
  796.             break;
  797.  
  798.         case OBJECTCODE_CLOSED:
  799.             if (NULL!=m_pIOleAdviseHolder)
  800.                 m_pIOleAdviseHolder->SendOnClose();
  801.  
  802.             break;
  803.  
  804.         case OBJECTCODE_RENAMED:
  805.             //Call IOleAdviseHolder::SendOnRename (later)
  806.             break;
  807.  
  808.         case OBJECTCODE_SAVEOBJECT:
  809.             if (m_fDirty && NULL!=m_pIOleClientSite)
  810.                 m_pIOleClientSite->SaveObject();
  811.  
  812.             m_fDirty=FALSE;
  813.             break;
  814.  
  815.         case OBJECTCODE_DATACHANGED:
  816.             m_fDirty=TRUE;
  817.  
  818.             //No flags are necessary here.
  819.             if (NULL!=m_pIDataAdviseHolder)
  820.                 {
  821.                 m_pIDataAdviseHolder->SendOnDataChange
  822.                     (m_pImpIDataObject, 0, 0);
  823.                 }
  824.  
  825.             if (NULL!=m_pIAdviseSink
  826.                 & (dwAspect & m_dwAdviseAspects))
  827.                 {
  828.                 m_pIAdviseSink->OnViewChange(dwAspect
  829.                     & m_dwAdviseAspects, 0);
  830.                 }
  831.  
  832.             break;
  833.  
  834.         case OBJECTCODE_SHOWWINDOW:
  835.             if (NULL!=m_pIOleClientSite)
  836.                 m_pIOleClientSite->OnShowWindow(TRUE);
  837.  
  838.             break;
  839.  
  840.         case OBJECTCODE_HIDEWINDOW:
  841.             if (NULL!=m_pIOleClientSite)
  842.                 m_pIOleClientSite->OnShowWindow(FALSE);
  843.  
  844.             break;
  845.  
  846.         case OBJECTCODE_SHOWOBJECT:
  847.             if (NULL!=m_pIOleClientSite)
  848.                 m_pIOleClientSite->ShowObject();
  849.  
  850.             break;
  851.         }
  852.  
  853.     return;
  854.     }
  855.  
  856.  
  857. //End CHAPTER19MOD
  858.