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

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