home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / oleaut / lines / points.cpp < prev    next >
C/C++ Source or Header  |  1997-07-31  |  15KB  |  581 lines

  1. /*************************************************************************
  2. **
  3. **  This is a part of the Microsoft Source Code Samples.
  4. **
  5. **  Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
  6. **
  7. **  This source code is only intended as a supplement to Microsoft Development
  8. **  Tools and/or WinHelp documentation.  See these sources for detailed
  9. **  information regarding the Microsoft samples programs.
  10. **
  11. **  OLE Automation Points object
  12. **
  13. **  points.cpp
  14. **
  15. **  CPoints collection implementation
  16. **
  17. **  Written by Microsoft Product Support Services, Windows Developer Support
  18. **
  19. *************************************************************************/
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #ifdef WIN16   
  24.   #include <ole2.h>
  25.   #include <compobj.h>    
  26.   #include <dispatch.h> 
  27.   #include <variant.h>
  28.   #include <olenls.h>  
  29. #endif      
  30. #include "lines.h"  
  31.  
  32. /*
  33.  * CPoints::Create
  34.  *
  35.  * Purpose:
  36.  *  Creates an instance of a collection object and initializes it.
  37.  *
  38.  * Parameters:
  39.  *  lMaxSize   Maximum number of items that can added to collection.
  40.  *  lLBound    Lower bound of index of collection.  
  41.  *  pPane      Pointer to pane that contains this collection. Required because the pane coordinates 
  42.  *             the lines and points collection.
  43.  *  ppPoints    Returns collection object.
  44.  *
  45.  * Return Value:
  46.  *  HRESULT
  47.  *
  48.  */
  49. HRESULT 
  50. CPoints::Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CPoints FAR* FAR* ppPoints) 
  51. {   
  52.     HRESULT hr;
  53.     CPoints FAR* pPoints = NULL;
  54.     SAFEARRAYBOUND sabound[1];
  55.      
  56.     *ppPoints = NULL;
  57.     
  58.     // Create new collection
  59.     pPoints = new CPoints();
  60.     if (pPoints == NULL)
  61.         goto error;
  62.     
  63.     pPoints->m_cMax = lMaxSize;
  64.     pPoints->m_cElements = 0; 
  65.     pPoints->m_lLBound = lLBound;     
  66.     pPoints->m_pPane = pPane;  
  67.     
  68.     // Load type information for the points collection from type library. 
  69.     hr = LoadTypeInfo(&pPoints->m_ptinfo, IID_IPoints);
  70.     if (FAILED(hr))
  71.         goto error;
  72.     
  73.     // Create a safe array which is used to implement the collection.            
  74.     sabound[0].cElements = lMaxSize;
  75.     sabound[0].lLbound = lLBound;        
  76.     pPoints->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  77.     if (pPoints->m_psa == NULL)
  78.     {
  79.         hr = E_OUTOFMEMORY;
  80.         goto error;
  81.     }             
  82.  
  83.     *ppPoints = pPoints;
  84.     return NOERROR;
  85.     
  86. error: 
  87.     if (pPoints == NULL)
  88.         return E_OUTOFMEMORY;
  89.     if (pPoints->m_ptinfo)
  90.         pPoints->m_ptinfo->Release();                            
  91.     if (pPoints->m_psa) 
  92.         SafeArrayDestroy(pPoints->m_psa); 
  93.   
  94.     pPoints->m_psa = NULL;
  95.     pPoints->m_ptinfo = NULL; 
  96.     
  97.     delete pPoints;
  98.     return hr;
  99. }
  100.  
  101. /*
  102.  * CPoints::CPoints
  103.  *
  104.  * Purpose:
  105.  *  Constructor for CPoints object. Initializes members to NULL.
  106.  *
  107.  */
  108. #pragma warning (disable : 4355)
  109. CPoints::CPoints() : m_SupportErrorInfo(this, IID_IPoints)
  110. #pragma warning (default : 4355)
  111. {    
  112.     m_cRef = 0;
  113.     m_psa = NULL;
  114.     m_ptinfo = NULL; 
  115. }
  116.  
  117. /*
  118.  * CPoints::~CPoints
  119.  *
  120.  * Purpose:
  121.  *  Destructor for CPoints object. 
  122.  *
  123.  */
  124. CPoints::~CPoints()
  125. {    
  126.      if (m_ptinfo) m_ptinfo->Release();                   
  127.      if (m_psa) SafeArrayDestroy(m_psa);
  128. }
  129.  
  130. /*
  131.  * CPoints::QueryInterface, AddRef, Release
  132.  *
  133.  * Purpose:
  134.  *  Implements IUnknown::QueryInterface, AddRef, Release
  135.  *
  136.  */
  137. STDMETHODIMP
  138. CPoints::QueryInterface(REFIID iid, void FAR* FAR* ppv) 
  139. {    
  140.     *ppv = NULL;
  141.         
  142.     if (iid == IID_IUnknown || iid == IID_IPoints || iid == IID_IDispatch)
  143.         *ppv = this;        
  144.     else if (iid == IID_ISupportErrorInfo)
  145.         *ppv = &m_SupportErrorInfo;
  146.     else return E_NOINTERFACE; 
  147.  
  148.     AddRef();
  149.     return NOERROR;    
  150. }
  151.  
  152.  
  153. STDMETHODIMP_(ULONG)
  154. CPoints::AddRef(void)
  155.  
  156. #ifdef _DEBUG  
  157.     TCHAR ach[50];
  158.     wsprintf(ach, TEXT("Ref = %ld, Points\r\n"), m_cRef+1); 
  159.     OutputDebugString(ach); 
  160. #endif  
  161.     
  162.     return ++m_cRef;
  163. }
  164.  
  165.  
  166. STDMETHODIMP_(ULONG)
  167. CPoints::Release(void)
  168.  
  169. #ifdef _DEBUG  
  170.     TCHAR ach[50];
  171.     wsprintf(ach, TEXT("Ref = %ld, Points\r\n"), m_cRef-1); 
  172.     OutputDebugString(ach);   
  173. #endif
  174.     
  175.     if(--m_cRef == 0)
  176.     {
  177.         delete this;
  178.         return 0;
  179.     }
  180.     return m_cRef;
  181.  
  182. /*
  183.  * CPoints::GetTypeInfoCount
  184.  *
  185.  * Purpose:
  186.  *  Implements IDispatch::GetTypeInfoCount.
  187.  *
  188.  */
  189. STDMETHODIMP
  190. CPoints::GetTypeInfoCount(UINT FAR* pctinfo)
  191. {
  192.     *pctinfo = 1;
  193.     return NOERROR;
  194. }
  195.  
  196. /*
  197.  * CPoints::GetTypeInfo
  198.  *
  199.  * Purpose:
  200.  *  Implements IDispatch::GetTypeInfo. 
  201.  *
  202.  */
  203. STDMETHODIMP
  204. CPoints::GetTypeInfo(
  205.       UINT itinfo,
  206.       LCID lcid,
  207.       ITypeInfo FAR* FAR* pptinfo)
  208. {    
  209.     *pptinfo = NULL;
  210.      
  211.     if(itinfo != 0)
  212.         return DISP_E_BADINDEX;
  213.     
  214.     m_ptinfo->AddRef(); 
  215.     *pptinfo = m_ptinfo;
  216.     
  217.     return NOERROR;
  218. }
  219.  
  220. /*
  221.  * CPoints::GetIDsOfNames
  222.  *
  223.  * Purpose:
  224.  *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,
  225.  *  is used.
  226.  *
  227.  */
  228. STDMETHODIMP 
  229. CPoints::GetIDsOfNames(
  230.       REFIID riid,
  231.       OLECHAR FAR* FAR* rgszNames,
  232.       UINT cNames,
  233.       LCID lcid,
  234.       DISPID FAR* rgdispid)
  235. {
  236.     return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);
  237. }
  238.  
  239. /*
  240.  * CPoints::Invoke
  241.  *
  242.  * Purpose:
  243.  *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,
  244.  *  is used. 
  245.  *
  246.  */
  247. STDMETHODIMP
  248. CPoints::Invoke(
  249.       DISPID dispidMember,
  250.       REFIID riid,
  251.       LCID lcid,
  252.       WORD wFlags,
  253.       DISPPARAMS FAR* pdispparams,
  254.       VARIANT FAR* pvarResult,
  255.       EXCEPINFO FAR* pexcepinfo,
  256.       UINT FAR* puArgErr)
  257. {  
  258.     return DispInvoke(
  259.         this, m_ptinfo,
  260.         dispidMember, wFlags, pdispparams,
  261.         pvarResult, pexcepinfo, puArgErr);   
  262. }
  263.  
  264. /*
  265.  * CPoints::get_Count
  266.  *
  267.  * Purpose:
  268.  *  Returns number of items in collection.
  269.  *
  270.  */
  271. STDMETHODIMP   
  272. CPoints::get_Count(long FAR* plCount)  
  273. {
  274.     *plCount = m_cElements;
  275.     return NOERROR;             
  276. }
  277.  
  278. /*
  279.  * CPoints::get_Item
  280.  *
  281.  * Purpose:
  282.  *  Retrieves item from collection, given an index.
  283.  *
  284.  * Parameters:   
  285.  *   lIndex   Index of item to be retrieved. 
  286.  *
  287.  * Returns
  288.  *  IDispatch of item retrieved from collection.
  289.  *
  290.  */
  291. STDMETHODIMP
  292. CPoints::get_Item(long lIndex, IPoint FAR* FAR* ppPoint)
  293.     HRESULT hr;
  294.     VARIANT v;
  295.     LPDISPATCH pdisp = NULL;
  296.    
  297.     // Check if integer index is within range         
  298.     if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements)) 
  299.         return RaiseException(IDS_InvalidIndex, IID_IPoints); 
  300.     
  301.     // Retrieve and return item. Note that SafeArrayGetElement AddRefs so an additional AddRef
  302.     // is not required.
  303.     VariantInit(&v);
  304.     hr = SafeArrayGetElement(m_psa, &lIndex, &v);
  305.     if (FAILED(hr))
  306.         return RaiseException(IDS_Unexpected, IID_IPoints); 
  307.     *ppPoint = (IPoint FAR*) V_DISPATCH(&v);    
  308.     return NOERROR;
  309. }
  310.  
  311. /*
  312.  * CPoints::get_NewEnum
  313.  *
  314.  * Purpose:
  315.  *  Returns an enumerator (IEnumVARIANT) for the items curently in the collection. 
  316.  *  The NewEnum property is restricted and so is invisible to users of an 
  317.  *  automation controller's scripting language. Automation controllers that support
  318.  *  a 'For Each' statement to iterate through the elements of a collection will use
  319.  *  the enumerator returned by NewEnum. The enumerator creates a snapshot of the
  320.  *  the current state of the collection.
  321.  *
  322.  */
  323. STDMETHODIMP
  324. CPoints::get__NewEnum(IUnknown FAR* FAR* ppunkEnum)
  325. {
  326.     CEnumVariant FAR* penum = NULL;
  327.     HRESULT hr;
  328.     
  329.     // Create new enumerator for items currently in collection and QI for IUnknown
  330.     hr = CEnumVariant::Create(m_psa, m_cElements, &penum);
  331.     if (FAILED(hr))
  332.         {hr = RaiseException(IDS_OutOfMemory, IID_IPoints); goto error;}       
  333.     hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)ppunkEnum);    
  334.     if (FAILED(hr)) 
  335.         {hr = RaiseException(IDS_Unexpected, IID_IPoints); goto error;}         
  336.     return NOERROR; 
  337.     
  338. error:
  339.     if (penum)
  340.         delete penum;    
  341.     return hr;              
  342. }
  343.  
  344. /* 
  345.  *
  346.  * The following methods are not exposed through Automation
  347.  *
  348.  */
  349.  
  350. /*
  351.  * CPoints::Add
  352.  *
  353.  * Purpose:
  354.  *  Adds an item to the collection. The points collection does not have duplicates.
  355.  *
  356.  * Parameters:
  357.  *  pPointAdd    Point to be added to collection.
  358.  *
  359.  */
  360. STDMETHODIMP_(BOOL)   
  361. CPoints::Add(CPoint FAR* pPointAdd)
  362.     HRESULT hr;   
  363.     LONG l;
  364.     VARIANT v;  
  365.     VARIANT HUGEP *pvar;
  366.     int nX, nY;
  367.     BOOL bFound = FALSE;     
  368.     LPDISPATCH pdispPointAdd = NULL;
  369.     CPoint FAR *pPoint;
  370.     LPDISPATCH pdispPoint;   
  371.     
  372.     // Is the collection full?
  373.     if (m_cElements == m_cMax) 
  374.         goto error;              
  375.        
  376.     // Get coordinates of point to be added to collection 
  377.     nX = pPointAdd->get_x();
  378.     nY = pPointAdd->get_y();
  379.           
  380.     hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);
  381.     if (FAILED(hr))
  382.         goto error; 
  383.               
  384.     // Check if point to be added is already in the collection.       
  385.     for (l=0; l<(long)m_cElements; l++)
  386.     {   
  387.         pdispPoint = V_DISPATCH(&pvar[l]);      
  388.         hr = pdispPoint->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);
  389.         if (FAILED(hr))
  390.             continue;                
  391.         if (nX == pPoint->get_x() &&  nY == pPoint->get_y())
  392.         {   
  393.             // Point is already in the collection. AddRef it.   
  394.             // Internal AddRef keeps track of number of times this point was added to this collection. When
  395.             //    this internal ref count drops to 0, this point can be removed from this collection.  
  396.             pPoint->InternalAddRef();        
  397.             pdispPoint->AddRef();  
  398.             
  399.             bFound = TRUE;
  400.             pPoint->Release(); 
  401.             break; 
  402.         }             
  403.         pPoint->Release();        
  404.     }   
  405.     hr = SafeArrayUnaccessData(m_psa);
  406.     if (FAILED(hr))
  407.        goto error;
  408.            
  409.     // Add point if it was not in the collection.
  410.     if (!bFound)
  411.     {
  412.         l = m_lLBound+m_cElements;    
  413.  
  414.         hr = pPointAdd->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdispPointAdd);
  415.         if (FAILED(hr))
  416.             goto error;              
  417.         VariantInit(&v);
  418.         V_VT(&v) = VT_DISPATCH;
  419.         V_DISPATCH(&v) = pdispPointAdd;    
  420.         hr = SafeArrayPutElement(m_psa, &l, &v);
  421.         if (FAILED(hr))
  422.             goto error;   
  423.             
  424.         // Internal AddRef keeps track of number of times this point was added to this collection. When
  425.         //    this internal ref count drops to 0, this point can be removed from this collection.       
  426.         pPointAdd->InternalAddRef();  
  427.         pdispPointAdd->Release();   
  428.           
  429.         m_cElements++;
  430.     }                    
  431.     return TRUE;    
  432.     
  433. error:
  434.     if (pdispPointAdd)
  435.         pdispPointAdd->Release();     
  436.     return FALSE;   
  437. }
  438.  
  439. /*
  440.  * CPoints::Remove
  441.  *
  442.  * Purpose:
  443.  *  Removes specified item from collection. The points collection does not have duplicates.
  444.  *
  445.  * Parameters:   
  446.  *   pPointRemove    Point to be removed from collection.
  447.  *
  448.  */
  449. STDMETHODIMP_(BOOL)
  450. CPoints::Remove(CPoint FAR* pPointRemove)
  451. {
  452.     HRESULT hr;
  453.     long l, lIndex;
  454.     VARIANT HUGEP *pvar;
  455.     ULONG cRef;
  456.     int nX, nY;
  457.     CPoint FAR* pPoint = NULL;
  458.     BOOL bFound = FALSE;    
  459.     BOOL bRet = FALSE;
  460.     
  461.     // Get coordinates of point to be removed from collection
  462.     nX = pPointRemove->get_x();
  463.     nY = pPointRemove->get_y();
  464.           
  465.     hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);
  466.     if (FAILED(hr))
  467.        goto error; 
  468.  
  469.               
  470.     // Check if point to be removed is in the collection.       
  471.     for (l=0; l<(long)m_cElements; l++)
  472.     {        
  473.         hr = V_DISPATCH(&pvar[l])->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);
  474.         if (FAILED(hr))
  475.             continue;
  476.                   
  477.         if (nX == pPoint->get_x() &&  nY == pPoint->get_y())
  478.         {
  479.             // Release point. Note that this collection does not have duplicates. Duplicate
  480.             // points are handled by increasing the ref count.
  481.             V_DISPATCH(&pvar[l])->Release();     
  482.             cRef = pPoint->InternalRelease();  
  483.             bFound = TRUE;
  484.             lIndex = l;
  485.             pPoint->Release(); 
  486.             break; 
  487.         }             
  488.         pPoint->Release();        
  489.     }   
  490.     
  491.     // If the internal ref count of point to be removed has dropped to 0, move up the array elements
  492.     // after the element to be removed.     
  493.     if (bFound && cRef == 0)
  494.     {           
  495.         for (l=lIndex; l<(long)(m_cElements-1); l++)  
  496.             pvar[l] = pvar[l+1];
  497.     
  498.         // Remove last element.    
  499.         V_VT(&pvar[l]) = VT_EMPTY;
  500.         m_cElements--; 
  501.         bRet = TRUE;
  502.     }
  503.             
  504.     hr = SafeArrayUnaccessData(m_psa);
  505.     if (FAILED(hr))
  506.        goto error;          
  507.     return bRet; 
  508.        
  509. error: 
  510.     return FALSE;
  511. }
  512.  
  513. /*
  514.  * CPoints::Clear
  515.  *
  516.  * Purpose:
  517.  *  Removes all items from collection.
  518.  *
  519.  */
  520. STDMETHODIMP_(void)
  521. CPoints::Clear(void)
  522. {
  523.     SafeArrayDestroyData(m_psa);     
  524.     SafeArrayAllocData(m_psa);
  525.     m_cElements = 0;
  526. }    
  527.  
  528. /*
  529.  * CPoints::GetMaxXMaxY
  530.  *
  531.  * Purpose:
  532.  *  Get the maximum X and Y coordinates that are in the rectangle, prc.
  533.  *
  534.  */
  535. STDMETHODIMP_(void)
  536. CPoints::GetMaxXMaxY(int FAR *pnX, int FAR *pnY, LPRECT prc)
  537. {   
  538.     HRESULT hr;
  539.     long l;
  540.     VARIANT HUGEP *pvar;
  541.     int nMaxX, nMaxY;       
  542.     CPoint FAR* pPoint;
  543.     POINT pt;
  544.     
  545.     hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);
  546.     if (FAILED(hr))
  547.        return; 
  548.  
  549.     nMaxX = -1; nMaxY = -1;
  550.     
  551.     // Find the maximume X and Y coordinates that are in the prc rectangle.    
  552.     for (l=0; l<(long)m_cElements; l++)
  553.     {        
  554.         V_DISPATCH(&pvar[l])->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);
  555.         pt.x = pPoint->get_x(); 
  556.         pt.y = pPoint->get_y();
  557.          
  558.         if (PtInRect(prc, pt))
  559.         {   
  560.             if (pt.x > nMaxX)
  561.                 nMaxX = pt.x;
  562.             
  563.             if (pt.y > nMaxY)
  564.                 nMaxY = pt.y;
  565.         }        
  566.         pPoint->Release();
  567.     }
  568.     
  569.     *pnX = nMaxX;
  570.     *pnY = nMaxY;    
  571.     
  572.     SafeArrayUnaccessData(m_psa);  
  573.     return;
  574. }  
  575.  
  576.