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 / chap24 / polyline / polyline.cpp < prev    next >
C/C++ Source or Header  |  1996-05-22  |  33KB  |  1,388 lines

  1. /*
  2.  * POLYLINE.CPP
  3.  * Polyline Component Chapter 24
  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.     m_pImpIExternalConnection=NULL;
  79.     m_fLockContainer=FALSE;
  80.     m_dwRegROT=0L;
  81.  
  82.     m_pIOleIPSite=NULL;
  83.     m_pIOleIPFrame=NULL;
  84.     m_pIOleIPUIWindow=NULL;
  85.     m_pImpIOleIPObject=NULL;
  86.     m_pImpIOleIPActiveObject=NULL;
  87.     m_hMenuShared=NULL;
  88.     m_hOLEMenu=NULL;
  89.     m_pHW=NULL;
  90.     m_fAllowInPlace=TRUE;
  91.     m_fUIActive=FALSE;
  92.  
  93.     m_fContainerKnowsInsideOut=FALSE;
  94.  
  95.     //CHAPTER24MOD
  96.     m_pImpISpecifyPP=NULL;
  97.     m_pImpIProvideClassInfo=NULL;
  98.     m_pImpIDispatch=NULL;
  99.     m_pImpIPolylineControl=NULL;
  100.     m_pImpIOleControl=NULL;
  101.  
  102.     m_pITypeLib=NULL;
  103.     m_pIOleControlSite=NULL;
  104.     m_pIDispatchAmbients=NULL;
  105.     m_fFreezeEvents=FALSE;
  106.  
  107.     m_fHatch=TRUE;
  108.     m_fUIDead=FALSE;
  109.     //End CHAPTER24MOD
  110.  
  111.     return;
  112.     }
  113.  
  114.  
  115. CPolyline::~CPolyline(void)
  116.     {
  117.     LPUNKNOWN       pIUnknown=this;
  118.  
  119.     if (NULL!=m_pUnkOuter)
  120.         pIUnknown=m_pUnkOuter;
  121.  
  122.     if (NULL!=m_pST)
  123.         delete m_pST;
  124.  
  125.     if (NULL!=m_hDlg)
  126.         DestroyWindow(m_hDlg);
  127.  
  128.     /*
  129.      * In aggregation, release cached pointers but
  130.      * AddRef the controlling unknown first.  The 
  131.      * extra reference count protects from reentrancy.
  132.      */
  133.  
  134.     m_cRef++;
  135.  
  136.     pIUnknown->AddRef();
  137.     pIUnknown->AddRef();
  138.     pIUnknown->AddRef();
  139.  
  140.     ReleaseInterface(m_pDefIViewObject);
  141.     ReleaseInterface(m_pDefIDataObject);
  142.     ReleaseInterface(m_pDefIPersistStorage);
  143.  
  144.     m_cRef--;
  145.  
  146.     //Cached pointer rules do not apply to IUnknown
  147.     ReleaseInterface(m_pDefIUnknown);
  148.  
  149.     ReleaseInterface(m_pIAdviseSink);
  150.     ReleaseInterface(m_pIOleClientSite);
  151.     ReleaseInterface(m_pIOleAdviseHolder);
  152.  
  153.     DeleteInterfaceImp(m_pImpIOleObject);
  154.     DeleteInterfaceImp(m_pImpIViewObject);
  155.     DeleteInterfaceImp(m_pImpIRunnableObject);
  156.  
  157.     //Other in-place interfaces released in deactivation.
  158.     DeleteInterfaceImp(m_pImpIOleIPObject);
  159.     DeleteInterfaceImp(m_pImpIOleIPActiveObject);
  160.  
  161.     //CHAPTER24MOD
  162.     ReleaseInterface(m_pIDispatchAmbients);
  163.     ReleaseInterface(m_pIOleControlSite);
  164.     ReleaseInterface(m_pITypeLib);
  165.  
  166.     DeleteInterfaceImp(m_pImpISpecifyPP);
  167.     DeleteInterfaceImp(m_pImpIProvideClassInfo);
  168.     DeleteInterfaceImp(m_pImpIDispatch);
  169.     DeleteInterfaceImp(m_pImpIPolylineControl);
  170.     DeleteInterfaceImp(m_pImpIOleControl);
  171.     //End CHAPTER24MOD
  172.  
  173.     //Anything we might have registered in IRunnableObject::Run
  174.     INOLE_RevokeAsRunning(&m_dwRegROT);
  175.  
  176.     DeleteInterfaceImp(m_pImpIExternalConnection);
  177.     ReleaseInterface(m_pIDataAdviseHolder);
  178.     DeleteInterfaceImp(m_pImpIDataObject);
  179.  
  180.     DeleteInterfaceImp(m_pImpIPersistStreamInit);
  181.     DeleteInterfaceImp(m_pImpIPersistStorage);
  182.     ReleaseInterface(m_pIStream);
  183.     ReleaseInterface(m_pIStorage);
  184.  
  185.     DeleteInterfaceImp(m_pImpIConnPtCont);
  186.     DeleteInterfaceImp(m_pImpIPolyline);
  187.  
  188.     ReleaseInterface(m_pAdv);
  189.     ReleaseInterface(m_pConnPt);
  190.  
  191.     return;
  192.     }
  193.  
  194.  
  195.  
  196.  
  197. /*
  198.  * CPolyline::Init
  199.  *
  200.  * Purpose:
  201.  *  Performs any intiailization of a CPolyline that's prone to
  202.  *  failure that we also use internally before exposing the
  203.  *  object outside this DLL.
  204.  *
  205.  * Parameters:
  206.  *  None
  207.  *
  208.  * Return Value:
  209.  *  BOOL            TRUE if the function is successful,
  210.  *                  FALSE otherwise.
  211.  */
  212.  
  213. BOOL CPolyline::Init(void)
  214.     {
  215.     LPUNKNOWN       pIUnknown=this;
  216.     HRESULT         hr;
  217.  
  218.     if (NULL!=m_pUnkOuter)
  219.         pIUnknown=m_pUnkOuter;
  220.  
  221.     m_pST=new CStringTable(m_hInst);
  222.  
  223.     if (!m_pST->Init(IDS_POLYLINEMIN, IDS_POLYLINEMAX))
  224.         return FALSE;
  225.  
  226.     m_cf=RegisterClipboardFormat(SZPOLYLINECLIPFORMAT);
  227.  
  228.     m_pImpIPersistStorage=new CImpIPersistStorage(this, pIUnknown);
  229.  
  230.     if (NULL==m_pImpIPersistStorage)
  231.         return FALSE;
  232.  
  233.     m_pImpIPersistStreamInit=new CImpIPersistStreamInit(this
  234.         , pIUnknown);
  235.  
  236.     if (NULL==m_pImpIPersistStreamInit)
  237.         return FALSE;
  238.  
  239.     m_pImpIPolyline=new CImpIPolyline(this, pIUnknown);
  240.  
  241.     if (NULL==m_pImpIPolyline)
  242.         return FALSE;
  243.  
  244.     m_pImpIConnPtCont=new CImpIConnPtCont(this, pIUnknown);
  245.  
  246.     if (NULL==m_pImpIConnPtCont)
  247.         return FALSE;
  248.  
  249.     m_pConnPt=new CConnectionPoint(this);
  250.  
  251.     if (NULL==m_pConnPt)
  252.         return FALSE;
  253.  
  254.     m_pConnPt->AddRef();    //Reversed in destructor
  255.  
  256.     m_pImpIDataObject=new CImpIDataObject(this, pIUnknown);
  257.  
  258.     if (NULL==m_pImpIDataObject)
  259.         return FALSE;
  260.  
  261.     m_pImpIOleObject=new CImpIOleObject(this, pIUnknown);
  262.  
  263.     if (NULL==m_pImpIOleObject)
  264.         return FALSE;
  265.  
  266.     m_pImpIViewObject=new CImpIViewObject(this, pIUnknown);
  267.  
  268.     if (NULL==m_pImpIViewObject)
  269.         return FALSE;
  270.  
  271.     m_pImpIRunnableObject=new CImpIRunnableObject(this, pIUnknown);
  272.  
  273.     if (NULL==m_pImpIRunnableObject)
  274.         return FALSE;
  275.  
  276.     m_pImpIExternalConnection=new CImpIExternalConnection(this
  277.         , pIUnknown);
  278.  
  279.     if (NULL==m_pImpIExternalConnection)
  280.         return FALSE;
  281.  
  282.     m_pImpIOleIPObject=new CImpIOleInPlaceObject(this, pIUnknown);
  283.  
  284.     if (NULL==m_pImpIOleIPObject)
  285.         return FALSE;
  286.  
  287.     m_pImpIOleIPActiveObject=new CImpIOleInPlaceActiveObject(this
  288.         , pIUnknown);
  289.  
  290.     if (NULL==m_pImpIOleIPActiveObject)
  291.         return FALSE;
  292.  
  293.     //CHAPTER24MOD
  294.     m_pImpISpecifyPP=new CImpISpecifyPP(this, pIUnknown);
  295.  
  296.     if (NULL==m_pImpISpecifyPP)
  297.         return FALSE;
  298.  
  299.     m_pImpIProvideClassInfo=new CImpIProvideClassInfo(this, pIUnknown);
  300.  
  301.     if (NULL==m_pImpIProvideClassInfo)
  302.         return FALSE;
  303.  
  304.     m_pImpIDispatch=new CImpIDispatch(this, pIUnknown);
  305.  
  306.     if (NULL==m_pImpIDispatch)
  307.         return FALSE;
  308.  
  309.     m_pImpIPolylineControl=new CImpIPolylineControl(this, pIUnknown);
  310.  
  311.     if (NULL==m_pImpIPolylineControl)
  312.         return FALSE;
  313.  
  314.     m_pImpIOleControl=new CImpIOleControl(this, pIUnknown);
  315.  
  316.     if (NULL==m_pImpIOleControl)
  317.         return FALSE;
  318.     //End CHAPTER24MOD
  319.  
  320.     /*
  321.      * We're sitting at ref count 0 and the next call will AddRef a
  322.      * few times and Release a few times.  This insures we don't
  323.      * delete ourselves prematurely.
  324.      */
  325.     m_cRef++;
  326.  
  327.     //Aggregate OLE's cache for IOleCache* interfaces.
  328.     hr=CreateDataCache(pIUnknown, CLSID_Polyline19
  329.         , IID_IUnknown, (PPVOID)&m_pDefIUnknown);
  330.  
  331.     if (FAILED(hr))
  332.         return FALSE;
  333.  
  334.     /*
  335.      * NOTE:  The spec specifically states that any interfaces
  336.      * besides IUnknown that we obtain on an aggregated object
  337.      * should be Released immediately after we QueryInterface for
  338.      * them because the QueryInterface will AddRef us, and since
  339.      * we would not release these interfaces until we were
  340.      * destroyed, we'd never go away because we'd never get a zero
  341.      * ref count.
  342.      */
  343.  
  344.     //Now try to get other interfaces to which we delegate
  345.     hr=m_pDefIUnknown->QueryInterface(IID_IViewObject2
  346.         , (PPVOID)&m_pDefIViewObject);
  347.  
  348.     if (FAILED(hr))
  349.         return FALSE;
  350.  
  351.     pIUnknown->Release();
  352.  
  353.     hr=m_pDefIUnknown->QueryInterface(IID_IDataObject
  354.         , (PPVOID)&m_pDefIDataObject);
  355.  
  356.     if (FAILED(hr))
  357.         return FALSE;
  358.  
  359.     pIUnknown->Release();
  360.  
  361.     hr=m_pDefIUnknown->QueryInterface(IID_IPersistStorage
  362.         , (PPVOID)&m_pDefIPersistStorage);
  363.  
  364.     if (FAILED(hr))
  365.         return FALSE;
  366.  
  367.     pIUnknown->Release();
  368.  
  369.     m_cRef--;
  370.     m_pImpIPolyline->New();
  371.  
  372.     //CHAPTER24MOD
  373.     /*
  374.      * Go load our own type information and save its ITypeLib
  375.      * pointer that will be used be CImpIDispatch and
  376.      * CImpIProvideClassInfo.
  377.      */
  378.  
  379.     hr=LoadRegTypeLib(LIBID_PolylineTypeLibrary, 1, 0
  380.         , LANG_NEUTRAL, &m_pITypeLib);
  381.  
  382.     if (FAILED(hr))
  383.         hr=LoadTypeLib(OLETEXT("POLYLINE.TLB"), &m_pITypeLib);
  384.  
  385.     if (FAILED(hr))
  386.         return FALSE;
  387.  
  388.     //Set up our CONTROLINFO structure (we have two mnemonics)
  389.     m_ctrlInfo.cb=sizeof(CONTROLINFO);
  390.     m_ctrlInfo.dwFlags=0;
  391.     m_ctrlInfo.hAccel=NULL;
  392.     m_ctrlInfo.cAccel=0;
  393.  
  394.     /*
  395.      * Note:  we cannot initialize ambients until we get
  396.      * a container interface pointer in IOleObject::SetClientSite.
  397.      */
  398.     //End CHAPTER24MOD
  399.  
  400.     return TRUE;
  401.     }
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409. /*
  410.  * CPolyline::QueryInterface
  411.  * CPolyline::AddRef
  412.  * CPolyline::Release
  413.  *
  414.  * Purpose:
  415.  *  IUnknown members for CPolyline object.
  416.  */
  417.  
  418. STDMETHODIMP CPolyline::QueryInterface(REFIID riid, PPVOID ppv)
  419.     {
  420.     *ppv=NULL;
  421.  
  422.     if (IID_IUnknown==riid)
  423.         *ppv=this;
  424.  
  425.     if (IID_IConnectionPointContainer==riid)
  426.         *ppv=m_pImpIConnPtCont;
  427.  
  428.     if (IID_IPolyline10==riid)
  429.         *ppv=m_pImpIPolyline;
  430.  
  431.     if (IID_IPersistStorage==riid)
  432.         *ppv=m_pImpIPersistStorage;
  433.  
  434.     if (IID_IPersist==riid || IID_IPersistStream==riid
  435.         || IID_IPersistStreamInit==riid)
  436.         *ppv=m_pImpIPersistStreamInit;
  437.  
  438.     if (IID_IDataObject==riid)
  439.         *ppv=m_pImpIDataObject;
  440.  
  441.     if (IID_IOleObject==riid)
  442.         *ppv=m_pImpIOleObject;
  443.  
  444.     if (IID_IViewObject==riid || IID_IViewObject2==riid)
  445.         *ppv=m_pImpIViewObject;
  446.  
  447.     if (IID_IRunnableObject==riid)
  448.         *ppv=m_pImpIRunnableObject;
  449.  
  450.     if (IID_IExternalConnection==riid)
  451.         *ppv=m_pImpIExternalConnection;
  452.  
  453.     //IOleWindow will be the InPlaceObject
  454.     if (IID_IOleWindow==riid || IID_IOleInPlaceObject==riid)
  455.         *ppv=m_pImpIOleIPObject;
  456.  
  457.     //CHAPTER24MOD
  458.     if (IID_ISpecifyPropertyPages==riid)
  459.         *ppv=m_pImpISpecifyPP;
  460.  
  461.     if (IID_IProvideClassInfo==riid)
  462.         *ppv=m_pImpIProvideClassInfo;
  463.  
  464.     if (IID_IDispatch==riid || DIID_DIPolylineControl==riid)
  465.         *ppv=m_pImpIDispatch;
  466.  
  467.     if (IID_IPolylineControl==riid)
  468.         *ppv=m_pImpIPolylineControl;
  469.  
  470.     if (IID_IOleControl==riid)
  471.         *ppv=m_pImpIOleControl;
  472.     //End CHAPTER24MOD
  473.  
  474.  
  475.     //Use the default handler's cache.
  476.     if (IID_IOleCache==riid || IID_IOleCache2==riid)
  477.         return m_pDefIUnknown->QueryInterface(riid, ppv);
  478.  
  479.     if (NULL!=*ppv)
  480.         {
  481.         ((LPUNKNOWN)*ppv)->AddRef();
  482.         return NOERROR;
  483.         }
  484.  
  485.     return ResultFromScode(E_NOINTERFACE);
  486.     }
  487.  
  488.  
  489. STDMETHODIMP_(ULONG) CPolyline::AddRef(void)
  490.     {
  491.     return ++m_cRef;
  492.     }
  493.  
  494.  
  495. STDMETHODIMP_(ULONG) CPolyline::Release(void)
  496.     {
  497.     if (0L!=--m_cRef)
  498.         return m_cRef;
  499.  
  500.     if (NULL!=m_pfnDestroy)
  501.         (*m_pfnDestroy)();
  502.  
  503.     delete this;
  504.     return 0L;
  505.     }
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513. /*
  514.  * CPolyline::RectConvertMappings
  515.  *
  516.  * Purpose:
  517.  *  Converts the contents of a rectangle from device (MM_TEXT) or
  518.  *  HIMETRIC to the other.
  519.  *
  520.  * Parameters:
  521.  *  pRect           LPRECT containing the rectangle to convert.
  522.  *  fToDevice       BOOL TRUE to convert from HIMETRIC to device,
  523.  *                  FALSE to convert device to HIMETRIC.
  524.  *
  525.  * Return Value:
  526.  *  None
  527.  */
  528.  
  529. void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
  530.     {
  531.     HDC      hDC;
  532.     int      iLpx, iLpy;
  533.  
  534.     if (NULL==pRect)
  535.         return;
  536.  
  537.     hDC=GetDC(NULL);
  538.     iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
  539.     iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
  540.     ReleaseDC(NULL, hDC);
  541.  
  542.     if (fToDevice)
  543.         {
  544.         pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
  545.         pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);
  546.  
  547.         pRect->right =MulDiv(iLpx, pRect->right, HIMETRIC_PER_INCH);
  548.         pRect->bottom=MulDiv(iLpy, pRect->bottom,HIMETRIC_PER_INCH);
  549.         }
  550.     else
  551.         {
  552.         pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
  553.         pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);
  554.  
  555.         pRect->right =MulDiv(pRect->right, HIMETRIC_PER_INCH, iLpx);
  556.         pRect->bottom=MulDiv(pRect->bottom,HIMETRIC_PER_INCH, iLpy);
  557.         }
  558.  
  559.     return;
  560.     }
  561.  
  562.  
  563.  
  564. /*
  565.  * CPolyline::DataSet
  566.  *
  567.  * Purpose:
  568.  *  Sets the current data in this Polyline to a given structure.
  569.  *
  570.  * Parameters:
  571.  *  pplIn           PPOLYLINEDATA to initialize to.
  572.  *  fSizeToData     BOOL indicating if we're to size to the data
  573.  *                  or scale it.
  574.  *  fNotify         BOOL indicating if we're to send an advise
  575.  *                  on this change.
  576.  *
  577.  * Return Value:
  578.  *  HRESULT         NOERROR if successful, otherwise a
  579.  *                  POLYLINE_E_ value.
  580.  */
  581.  
  582. STDMETHODIMP CPolyline::DataSet(PPOLYLINEDATA pplIn
  583.     , BOOL fSizeToData, BOOL fNotify)
  584.     {
  585.     RECT            rc;
  586.  
  587.     /*
  588.      * Copy the structure in pplIn and repaint to reflect the
  589.      * new point set.  Note that unlike the RectSet message, we
  590.      * do no scaling, assuming that the rect in the structure
  591.      * is appropriate for the data.
  592.      */
  593.  
  594.     if (NULL==pplIn)
  595.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  596.  
  597.     m_pl=*pplIn;
  598.     m_fDirty=TRUE;
  599.  
  600.     /*
  601.      * If we're scaling the window to fit the data, then use
  602.      * RectSet passing our current rectangle as the new one.
  603.      * That makes sure that the data won't change but that the
  604.      * window is resized.
  605.      */
  606.  
  607.     if (fSizeToData)
  608.         {
  609.         POINT       pt;
  610.  
  611.         /*
  612.          * Get our offset in the parent window so we can RectSet
  613.          * to the right place since RectSet expects rectangle in
  614.          * parent coordinates and we get it in client coordinates.
  615.          */
  616.         if (NULL!=m_hWnd)
  617.             {
  618.             GetWindowRect(m_hWnd, &rc);
  619.             pt.x=rc.left;
  620.             pt.y=rc.top;
  621.             ScreenToClient(GetParent(m_hWnd), &pt);
  622.             RECTSTORECT(m_pl.rc, rc);
  623.             OffsetRect(&rc, pt.x, pt.y);
  624.  
  625.             //This will also cause a repaint.
  626.             m_pImpIPolyline->RectSet(&rc, fNotify);
  627.             }
  628.         }
  629.     else
  630.         {
  631.         if (NULL!=m_hWnd)
  632.             {
  633.             //Make sure we're updated.
  634.             InvalidateRect(m_hWnd, NULL, TRUE);
  635.             UpdateWindow(m_hWnd);
  636.             }
  637.         }
  638.  
  639.     SendAdvise(OBJECTCODE_DATACHANGED);
  640.     return NOERROR;
  641.     }
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649. /*
  650.  * CPolyline::DataGet
  651.  *
  652.  * Purpose:
  653.  *  Retrieves the Polyline's current data.
  654.  *
  655.  * Parameters:
  656.  *  pplIn           PPOLYLINEDATA into which we copy the data.
  657.  *
  658.  * Return Value:
  659.  *  HRESULT         NOERROR if successful, otherwise a
  660.  *                  POLYLINE_E_ value.
  661.  */
  662.  
  663. STDMETHODIMP CPolyline::DataGet(PPOLYLINEDATA pplIn)
  664.     {
  665.     if (NULL==pplIn)
  666.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  667.  
  668.     *pplIn=m_pl;
  669.     return NOERROR;
  670.     }
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677. /*
  678.  * CPolyline::RenderNative
  679.  *
  680.  * Purpose:
  681.  *  Retrieves the Polyline's data in a global memory handle.
  682.  *
  683.  * Parameters:
  684.  *  phMem           HGLOBAL * in which to store the handle.
  685.  *
  686.  * Return Value:
  687.  *  HRESULT         NOERROR if successful, otherwise a
  688.  *                  POLYLINE_E_ value.
  689.  */
  690.  
  691. STDMETHODIMP CPolyline::RenderNative(HGLOBAL *phMem)
  692.     {
  693.     HGLOBAL         hMem;
  694.     PPOLYLINEDATA   ppl;
  695.     HRESULT         hr=ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  696.  
  697.     if (NULL==phMem)
  698.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  699.  
  700.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, CBPOLYLINEDATA);
  701.  
  702.     if (NULL!=hMem)
  703.         {
  704.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  705.         hr=DataGet(ppl);
  706.  
  707.         GlobalUnlock(hMem);
  708.  
  709.         if (FAILED(hr))
  710.             {
  711.             GlobalFree(hMem);
  712.             hMem=NULL;
  713.             }
  714.         }
  715.  
  716.     *phMem=hMem;
  717.     return hr;
  718.     }
  719.  
  720.  
  721.  
  722.  
  723. /*
  724.  * CPolyline::RenderBitmap
  725.  *
  726.  * Purpose:
  727.  *  Creates a bitmap image of the current Polyline.
  728.  *
  729.  * Parameters:
  730.  *  phBmp           HBITMAP * in which to return the bitmap.
  731.  *
  732.  * Return Value:
  733.  *  HRESULT         NOERROR if successful, otherwise a
  734.  *                  POLYLINE_E_ value.
  735.  */
  736.  
  737. STDMETHODIMP CPolyline::RenderBitmap(HBITMAP *phBmp)
  738.     {
  739.     HDC             hDC;
  740.     HDC             hMemDC;
  741.     HBITMAP         hBmp;
  742.     RECT            rc;
  743.     HGDIOBJ         hObj;
  744.  
  745.     if (NULL==phBmp)
  746.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  747.  
  748.     //Render a bitmap the size of the current rectangle.
  749.     hDC=GetDC(m_hWnd);
  750.     hMemDC=CreateCompatibleDC(hDC);
  751.  
  752.     GetClientRect(m_hWnd, &rc);
  753.     hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  754.  
  755.     if (NULL!=hBmp)
  756.         {
  757.         //Draw the POLYLINEDATA into the bitmap.
  758.         hObj=SelectObject(hMemDC, hBmp);
  759.         Draw(hMemDC, FALSE, TRUE, &rc, NULL);
  760.         SelectObject(hMemDC, hObj);
  761.         }
  762.  
  763.     DeleteDC(hMemDC);
  764.     ReleaseDC(m_hWnd, hDC);
  765.  
  766.     *phBmp=hBmp;
  767.     return NOERROR;
  768.     }
  769.  
  770.  
  771.  
  772. //RenderMetafile not necessary--now part of RenderMetafilePict.
  773.  
  774.  
  775.  
  776. /*
  777.  * CPolyline::RenderMetafilePict
  778.  *
  779.  * Purpose:
  780.  *  Renders the current Polyline into a METAFILEPICT structure in
  781.  *  global memory.
  782.  *
  783.  * Parameters:
  784.  *  phMem           HGLOBAL * in which to return the
  785.  *                  METAFILEPICT.
  786.  *
  787.  * Return Value:
  788.  *  HRESULT         NOERROR if successful, otherwise a
  789.  *                  POLYLINE_E_ value.
  790.  */
  791.  
  792. STDMETHODIMP CPolyline::RenderMetafilePict(HGLOBAL *phMem)
  793.     {
  794.     HGLOBAL         hMem;
  795.     HMETAFILE       hMF;
  796.     LPMETAFILEPICT  pMF;
  797.     RECT            rc;
  798.     HDC             hDC;
  799.  
  800.     if (NULL==phMem)
  801.         return ResultFromScode(POLYLINE_E_INVALIDPOINTER);
  802.  
  803.     //Create a memory metafile and return its handle.
  804.     hDC=(HDC)CreateMetaFile(NULL);
  805.  
  806.     if (NULL==hDC)
  807.         return ResultFromScode(STG_E_MEDIUMFULL);
  808.  
  809.     SetMapMode(hDC, MM_ANISOTROPIC);
  810.     GetClientRect(m_hWnd, &rc);
  811.     SetWindowOrgEx(hDC, 0, 0, NULL);
  812.     SetWindowExtEx(hDC, rc.right, rc.bottom, NULL);
  813.  
  814.     Draw(hDC, TRUE, TRUE, &rc, NULL);
  815.     hMF=CloseMetaFile(hDC);
  816.  
  817.     if (NULL==hMF)
  818.         return ResultFromScode(STG_E_MEDIUMFULL);
  819.  
  820.     //Allocate the METAFILEPICT structure.
  821.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  822.         , sizeof(METAFILEPICT));
  823.  
  824.     if (NULL==hMem)
  825.         {
  826.         DeleteMetaFile(hMF);
  827.         return ResultFromScode(E_FAIL);
  828.         }
  829.  
  830.     /*
  831.      * Global lock only fails in PMODE if the selector is invalid
  832.      * (like it was discarded) or references a 0 length segment,
  833.      * neither of which can happen here.
  834.      */
  835.     pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  836.  
  837.     pMF->hMF=hMF;
  838.     pMF->mm=MM_ANISOTROPIC;
  839.  
  840.     //Insert the extents in MM_HIMETRIC units.
  841.     GetClientRect(m_hWnd, &rc);
  842.     RectConvertMappings(&rc, FALSE);
  843.     pMF->xExt=rc.right;
  844.     pMF->yExt=rc.bottom;
  845.  
  846.     GlobalUnlock(hMem);
  847.  
  848.     *phMem=hMem;
  849.     return NOERROR;
  850.     }
  851.  
  852.  
  853.  
  854. /*
  855.  * CPolyline::Instance
  856.  *
  857.  * Purpose:
  858.  *  Provides access to the module instance.
  859.  *
  860.  * Parameters:
  861.  *  None
  862.  *
  863.  * Return Value:
  864.  *  HINSTANCE       The instance handle of the module.
  865.  */
  866.  
  867. HINSTANCE CPolyline::Instance(void)
  868.     {
  869.     return m_hInst;
  870.     }
  871.  
  872.  
  873.  
  874. /*
  875.  * CPolyline::String
  876.  *
  877.  * Purpose:
  878.  *  Provides string lookup in the Polyline string table.
  879.  *
  880.  * Parameters:
  881.  *  uID             UINT of the string to return.
  882.  *
  883.  * Return Value:
  884.  *  LPTSTR          Pointer to the string.
  885.  */
  886.  
  887. LPTSTR CPolyline::String(UINT uID)
  888.     {
  889.     return PSZ(uID);
  890.     }
  891.  
  892.  
  893.  
  894.  
  895. /*
  896.  * CPolyline::SendAdvise
  897.  *
  898.  * Purpose:
  899.  *  Calls the appropriate IOleClientSite or IAdviseSink member
  900.  *  function for various events such as closure, renaming, etc.
  901.  *
  902.  * Parameters:
  903.  *  uCode           UINT OBJECTCODE_* identifying the notification.
  904.  *
  905.  * Return Value:
  906.  *  None
  907.  */
  908.  
  909. void CPolyline::SendAdvise(UINT uCode)
  910.     {
  911.     DWORD       dwAspect=DVASPECT_CONTENT | DVASPECT_THUMBNAIL;
  912.  
  913.     switch (uCode)
  914.         {
  915.         case OBJECTCODE_SAVED:
  916.             if (NULL!=m_pIOleAdviseHolder)
  917.                 m_pIOleAdviseHolder->SendOnSave();
  918.             break;
  919.  
  920.         case OBJECTCODE_CLOSED:
  921.             if (NULL!=m_pIOleAdviseHolder)
  922.                 m_pIOleAdviseHolder->SendOnClose();
  923.  
  924.             break;
  925.  
  926.         case OBJECTCODE_RENAMED:
  927.             //Call IOleAdviseHolder::SendOnRename (later)
  928.             break;
  929.  
  930.         case OBJECTCODE_SAVEOBJECT:
  931.             if (m_fDirty && NULL!=m_pIOleClientSite)
  932.                 m_pIOleClientSite->SaveObject();
  933.  
  934.             m_fDirty=FALSE;
  935.             break;
  936.  
  937.         case OBJECTCODE_DATACHANGED:
  938.             m_fDirty=TRUE;
  939.  
  940.             //No flags are necessary here.
  941.             if (NULL!=m_pIDataAdviseHolder)
  942.                 {
  943.                 m_pIDataAdviseHolder->SendOnDataChange
  944.                     (m_pImpIDataObject, 0, 0);
  945.                 }
  946.  
  947.             if (NULL!=m_pIAdviseSink
  948.                 & (dwAspect & m_dwAdviseAspects))
  949.                 {
  950.                 m_pIAdviseSink->OnViewChange(dwAspect
  951.                     & m_dwAdviseAspects, 0);
  952.                 }
  953.  
  954.             break;
  955.  
  956.         case OBJECTCODE_SHOWWINDOW:
  957.             if (NULL!=m_pIOleClientSite)
  958.                 m_pIOleClientSite->OnShowWindow(TRUE);
  959.  
  960.             break;
  961.  
  962.         case OBJECTCODE_HIDEWINDOW:
  963.             if (NULL!=m_pIOleClientSite)
  964.                 m_pIOleClientSite->OnShowWindow(FALSE);
  965.  
  966.             break;
  967.  
  968.         case OBJECTCODE_SHOWOBJECT:
  969.             if (NULL!=m_pIOleClientSite)
  970.                 m_pIOleClientSite->ShowObject();
  971.  
  972.             break;
  973.         }
  974.  
  975.     return;
  976.     }
  977.  
  978.  
  979.  
  980.  
  981. /*
  982.  * CPolyline::InPlaceActivate
  983.  *
  984.  * Purpose:
  985.  *  Goes through all the steps of activating the Polyline as an
  986.  *  in-place object.
  987.  *
  988.  * Parameters:
  989.  *  pActiveSite     LPOLECLIENTSITE of the active site we show in.
  990.  *  fIncludeUI      BOOL controls whether we call UIActivate too.
  991.  *
  992.  * Return Value:
  993.  *  HRESULT         Whatever error code is appropriate.
  994.  */
  995.  
  996. HRESULT CPolyline::InPlaceActivate(LPOLECLIENTSITE pActiveSite
  997.     , BOOL fIncludeUI)
  998.     {
  999.     HRESULT                 hr;
  1000.     HWND                    hWnd;
  1001.     HWND                    hWndHW;
  1002.     RECT                    rcPos;
  1003.     RECT                    rcClip;
  1004.     OLEINPLACEFRAMEINFO     frameInfo;
  1005.  
  1006.     if (NULL==pActiveSite)
  1007.         return ResultFromScode(E_INVALIDARG);
  1008.  
  1009.     if (NULL!=m_pIOleIPSite)
  1010.         {
  1011.         if (fIncludeUI)
  1012.             UIActivate();
  1013.  
  1014.         return NOERROR;
  1015.         }
  1016.  
  1017.  
  1018.     //1.  Initialization, obtaining interfaces, OnInPlaceActivate.
  1019.     hr=pActiveSite->QueryInterface(IID_IOleInPlaceSite
  1020.         , (PPVOID)&m_pIOleIPSite);
  1021.  
  1022.     if (FAILED(hr))
  1023.         return hr;
  1024.  
  1025.     hr=m_pIOleIPSite->CanInPlaceActivate();
  1026.  
  1027.     if (NOERROR!=hr)
  1028.         {
  1029.         m_pIOleIPSite->Release();
  1030.         m_pIOleIPSite=NULL;
  1031.         return ResultFromScode(E_FAIL);
  1032.         }
  1033.  
  1034.     m_pIOleIPSite->OnInPlaceActivate();
  1035.  
  1036.  
  1037.     //2.  Get the window context and create a window.
  1038.     m_pIOleIPSite->GetWindow(&hWnd);
  1039.     frameInfo.cb=sizeof(OLEINPLACEFRAMEINFO);
  1040.  
  1041.     m_pIOleIPSite->GetWindowContext(&m_pIOleIPFrame
  1042.         , &m_pIOleIPUIWindow, &rcPos, &rcClip, &frameInfo);
  1043.  
  1044.  
  1045.     /*
  1046.      * Create the hatch window after we get a parent window.  We
  1047.      * could not create the hatch window sooner because had nothing
  1048.      * to use for the parent.
  1049.      */
  1050.     m_pHW=new CHatchWin(m_hInst);
  1051.  
  1052.     if (NULL==m_pHW)
  1053.         {
  1054.         InPlaceDeactivate();
  1055.         return ResultFromScode(E_OUTOFMEMORY);
  1056.         }
  1057.  
  1058.     if (!m_pHW->Init(hWnd, ID_HATCHWINDOW, NULL))
  1059.         {
  1060.         InPlaceDeactivate();
  1061.         return ResultFromScode(E_OUTOFMEMORY);
  1062.         }
  1063.  
  1064.  
  1065.     //Make sure dialog is hidden
  1066.     if (NULL!=m_hDlg)
  1067.         {
  1068.         ShowWindow(m_hDlg, SW_HIDE);
  1069.         SendAdvise(OBJECTCODE_HIDEWINDOW);
  1070.         }
  1071.  
  1072.     //Move the hatch window to the container window.
  1073.     hWndHW=m_pHW->Window();
  1074.     SetParent(hWndHW, hWnd);
  1075.  
  1076.     //Move the Polyline window from the hidden dialog to hatch window
  1077.     m_pHW->HwndAssociateSet(m_hWnd);
  1078.     m_pHW->ChildSet(m_hWnd);
  1079.     m_pHW->RectsSet(&rcPos, &rcClip);   //Positions polyline
  1080.  
  1081.     ///CHAPTER24MOD
  1082.     //This might be off when we get to here.
  1083.     if (!m_fHatch)
  1084.         m_pHW->ShowHatch(FALSE);
  1085.     //End CHAPTER24MOD
  1086.  
  1087.     ShowWindow(hWndHW, SW_SHOW);
  1088.     SendAdvise(OBJECTCODE_SHOWOBJECT);
  1089.  
  1090.     //Critical for accelerators to work initially.
  1091.     SetFocus(hWndHW);
  1092.  
  1093.     //3, 4, 5.  Do UI things: active object, shared menu, tools
  1094.     hr=NOERROR;
  1095.  
  1096.     if (fIncludeUI)
  1097.         hr=UIActivate();
  1098.  
  1099.     /*
  1100.      * Since we don't have an Undo while in-place, tell the continer
  1101.      * to free it's undo state immediately.
  1102.      */
  1103.     m_pIOleIPSite->DiscardUndoState();
  1104.  
  1105.     return hr;
  1106.     }
  1107.  
  1108.  
  1109.  
  1110.  
  1111. /*
  1112.  * CPolyline::InPlaceDeactivate
  1113.  *
  1114.  * Purpose:
  1115.  *  Reverses all the activation steps from InPlaceActivate.
  1116.  *
  1117.  * Parameters:
  1118.  *  None
  1119.  *
  1120.  * Return Value:
  1121.  *  None
  1122.  */
  1123.  
  1124. void CPolyline::InPlaceDeactivate(void)
  1125.     {
  1126.     UIDeactivate();
  1127.  
  1128.     if (NULL!=m_pHW)
  1129.         {
  1130.         RECT        rc;
  1131.  
  1132.         ShowWindow(m_pHW->Window(), SW_HIDE);
  1133.  
  1134.         //Reposition the polyline window in the dialog box.
  1135.         SetParent(m_hWnd, m_hDlg);
  1136.         CalcPolyRectInDialog(m_hDlg, &rc);
  1137.  
  1138.         SetWindowPos(m_hWnd, NULL, rc.left, rc.top
  1139.             , rc.right-rc.left, rc.bottom-rc.top, SWP_NOZORDER);
  1140.  
  1141.         m_pHW->ChildSet(NULL);
  1142.  
  1143.         delete m_pHW;
  1144.         m_pHW=NULL;
  1145.         }
  1146.  
  1147.     ReleaseInterface(m_pIOleIPFrame);
  1148.     ReleaseInterface(m_pIOleIPUIWindow)
  1149.  
  1150.     if (NULL!=m_pIOleIPSite)
  1151.         {
  1152.         m_pIOleIPSite->OnInPlaceDeactivate();
  1153.         ReleaseInterface(m_pIOleIPSite);
  1154.         }
  1155.  
  1156.     return;
  1157.     }
  1158.  
  1159.  
  1160.  
  1161. /*
  1162.  * CPolyline::UIActivate
  1163.  *
  1164.  * Purpose:
  1165.  *  Goes through all the steps of activating the user interface of
  1166.  *  Polyline as an in-place object.
  1167.  *
  1168.  * Parameters:
  1169.  *  None
  1170.  *
  1171.  * Return Value:
  1172.  *  HRESULT         NOERROR or error code.
  1173.  */
  1174.  
  1175. HRESULT CPolyline::UIActivate(void)
  1176.     {
  1177.     //1.  Call IOleInPlaceSite::UIActivate
  1178.     if (NULL!=m_pIOleIPSite)
  1179.         m_pIOleIPSite->OnUIActivate();
  1180.  
  1181.     //2.  Set the active object
  1182.    #ifdef WIN32ANSI
  1183.     OLECHAR     szTemp[40];
  1184.  
  1185.     MultiByteToWideChar(CP_ACP, 0, PSZ(IDS_USERTYPE)
  1186.         , -1, szTemp, 40);
  1187.    #endif
  1188.  
  1189.     if (NULL!=m_pIOleIPFrame)
  1190.         {
  1191.         m_pIOleIPFrame->SetActiveObject(m_pImpIOleIPActiveObject
  1192.            #ifdef WIN32ANSI
  1193.             , szTemp);
  1194.            #else
  1195.             , PSZ(IDS_USERTYPE));
  1196.            #endif
  1197.         }
  1198.  
  1199.     if (NULL!=m_pIOleIPUIWindow)
  1200.         {
  1201.         m_pIOleIPUIWindow->SetActiveObject(m_pImpIOleIPActiveObject
  1202.            #ifdef WIN32ANSI
  1203.             , szTemp);
  1204.            #else
  1205.             , PSZ(IDS_USERTYPE));
  1206.            #endif
  1207.         }
  1208.  
  1209.     //3.  Critical for accelerators to work initially.
  1210.     SetFocus(m_pHW->Window());
  1211.  
  1212.     //4.  Negotiate border space.  Polyline doesn't need any.
  1213.     if (NULL!=m_pIOleIPFrame)
  1214.         m_pIOleIPFrame->SetBorderSpace(NULL);
  1215.  
  1216.     if (NULL!=m_pIOleIPUIWindow)
  1217.         m_pIOleIPUIWindow->SetBorderSpace(NULL);
  1218.  
  1219.  
  1220.     /*
  1221.      * 5.  Create the shared menu.  We don't have any, so tell
  1222.      *     the container to use its own menu.
  1223.      */
  1224.  
  1225.     if (NULL!=m_pIOleIPFrame)
  1226.         m_pIOleIPFrame->SetMenu(NULL, NULL, m_hWnd);
  1227.  
  1228.     m_fUIActive=TRUE;
  1229.     return NOERROR;
  1230.     }
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236. /*
  1237.  * CPolyline::UIDeactivate
  1238.  *
  1239.  * Purpose:
  1240.  *  Reverses all the user interface activation steps from
  1241.  *  UIActivate.
  1242.  *
  1243.  * Parameters:
  1244.  *  None
  1245.  *
  1246.  * Return Value:
  1247.  *  None
  1248.  */
  1249.  
  1250. void CPolyline::UIDeactivate(void)
  1251.     {
  1252.     m_fUIActive=FALSE;
  1253.  
  1254.     //We don't have any shared menu or tools to clean up.
  1255.  
  1256.     //Clear out the active objects
  1257.     if (NULL!=m_pIOleIPFrame)
  1258.         m_pIOleIPFrame->SetActiveObject(NULL, NULL);
  1259.  
  1260.     if (NULL!=m_pIOleIPUIWindow)
  1261.         m_pIOleIPUIWindow->SetActiveObject(NULL, NULL);
  1262.  
  1263.     if (NULL!=m_pIOleIPSite)
  1264.         m_pIOleIPSite->OnUIDeactivate(FALSE);
  1265.  
  1266.     return;
  1267.     }
  1268.  
  1269.  
  1270. //CHAPTER24MOD
  1271.  
  1272. /*
  1273.  * AmbientGet
  1274.  *
  1275.  * Purpose:
  1276.  *  Retrieves a specific ambient property into a VARIANT.
  1277.  *
  1278.  * Parameters:
  1279.  *  dispID          DISPID of the property to retrieve.
  1280.  *  pva             VARIANT * to fill with the new value.
  1281.  *
  1282.  * Return value
  1283.  *  BOOL            TRUE if the ambient was retrieved, FALSE
  1284.  *                  otherwise.
  1285.  */
  1286.  
  1287. BOOL CPolyline::AmbientGet(DISPID dispID, VARIANT *pva)
  1288.     {
  1289.     HRESULT         hr;
  1290.     DISPPARAMS      dp;
  1291.  
  1292.     if (NULL==pva)
  1293.         return FALSE;
  1294.  
  1295.     if (NULL==m_pIDispatchAmbients)
  1296.         return FALSE;
  1297.  
  1298.     SETNOPARAMS(dp);
  1299.     hr=m_pIDispatchAmbients->Invoke(dispID, IID_NULL
  1300.         , LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET
  1301.         , &dp, pva, NULL, NULL);
  1302.  
  1303.     return SUCCEEDED(hr);
  1304.     }
  1305.  
  1306.  
  1307. /*
  1308.  * AmbientsInitialize
  1309.  *
  1310.  * Purpose:
  1311.  *  Attempts to retrieve the container's ambient properties
  1312.  *  and initialize (or reinitialize) Polyline accordingly.
  1313.  *
  1314.  * Parameters:
  1315.  *  dwWhich         DWORD containing INITAMBIENT_... flags
  1316.  *                  describing which ambients to initialize.
  1317.  *                  This can be any combination.
  1318.  *
  1319.  * Return Value:
  1320.  *  None
  1321.  */
  1322.  
  1323. void CPolyline::AmbientsInitialize(DWORD dwWhich)
  1324.     {
  1325.     VARIANT     va;
  1326.     COLORREF    cr;
  1327.  
  1328.     if (NULL==m_pIDispatchAmbients)
  1329.         return;
  1330.  
  1331.     /*
  1332.      * We need to retrieve these ambients into these variables:
  1333.      *
  1334.      *  Ambient Property:               Variable:
  1335.      *  -----------------------------------------------
  1336.      *  DISPID_AMBIENT_SHOWHATCHING     m_fHatch
  1337.      *  DISPID_AMBIENT_UIDEAD           m_fUIDead
  1338.      *  DISPID_AMBIENT_BACKCOLOR        m_pl.rgbBackground
  1339.      *  DISPID_AMBIENT_FORECOLOR        m_pl.rgbLine
  1340.      */
  1341.  
  1342.     if ((INITAMBIENT_SHOWHATCHING & dwWhich)
  1343.         &&AmbientGet(DISPID_AMBIENT_SHOWHATCHING, &va))
  1344.         {
  1345.         m_fHatch=V_BOOL(&va);
  1346.  
  1347.         if (NULL!=m_pHW)
  1348.             m_pHW->ShowHatch(m_fHatch);
  1349.         }
  1350.  
  1351.     if ((INITAMBIENT_UIDEAD & dwWhich)
  1352.         && AmbientGet(DISPID_AMBIENT_UIDEAD, &va))
  1353.         {
  1354.         //This affects our detection of mouse clicks
  1355.         m_fUIDead=V_BOOL(&va);
  1356.         }
  1357.  
  1358.     if ((INITAMBIENT_BACKCOLOR & dwWhich)
  1359.         && AmbientGet(DISPID_AMBIENT_BACKCOLOR, &va))
  1360.         {
  1361.         cr=V_I4(&va);
  1362.  
  1363.         if (0x80000000 & cr)
  1364.             cr=GetSysColor(cr & 0x7FFFFFFF);
  1365.  
  1366.         m_pl.rgbBackground=cr;
  1367.         InvalidateRect(m_hWnd, NULL, TRUE);
  1368.         UpdateWindow(m_hWnd);
  1369.         }
  1370.  
  1371.     if ((INITAMBIENT_FORECOLOR & dwWhich)
  1372.         && AmbientGet(DISPID_AMBIENT_FORECOLOR, &va))
  1373.         {
  1374.         cr=V_I4(&va);
  1375.  
  1376.         if (0x80000000 & cr)
  1377.             cr=GetSysColor(cr & 0x7FFFFFFF);
  1378.  
  1379.         m_pl.rgbLine=cr;
  1380.         InvalidateRect(m_hWnd, NULL, TRUE);
  1381.         UpdateWindow(m_hWnd);
  1382.         }
  1383.  
  1384.     return;
  1385.     }
  1386.  
  1387. //End CHAPTER24MOD
  1388.