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 / lines.cpp < prev    next >
C/C++ Source or Header  |  1997-07-31  |  12KB  |  514 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 Lines object
  12. **
  13. **  lines.cpp
  14. **
  15. **  CLines 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.  * CLines::Create
  34.  *
  35.  * Purpose:
  36.  *  Creates an instance of a Lines 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.  *  ppLines    Returns Lines collection object.
  44.  *
  45.  * Return Value:
  46.  *  HRESULT
  47.  *
  48.  */
  49. HRESULT
  50. CLines::Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CLines FAR* FAR* ppLines) 
  51. {   
  52.     HRESULT hr;
  53.     CLines FAR* pLines = NULL;
  54.     SAFEARRAYBOUND sabound[1];
  55.      
  56.     *ppLines = NULL;
  57.     
  58.     // Create new collection
  59.     pLines = new CLines();
  60.     if (pLines == NULL)
  61.         goto error;
  62.  
  63.     pLines->m_cMax = lMaxSize;
  64.     pLines->m_cElements = 0; 
  65.     pLines->m_lLBound = lLBound;
  66.     pLines->m_pPane = pPane;      
  67.     
  68.     // Load type information for the Lines collection from type library. 
  69.     hr = LoadTypeInfo(&pLines->m_ptinfo, IID_ILines);
  70.     if (FAILED(hr))
  71.         goto error;
  72.     
  73.     // Create a safe array of variants which is used to implement the collection.            
  74.     sabound[0].cElements = lMaxSize;
  75.     sabound[0].lLbound = lLBound;        
  76.     pLines->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  77.     if (pLines->m_psa == NULL)
  78.     {
  79.         hr = E_OUTOFMEMORY;
  80.         goto error;
  81.     }             
  82.  
  83.     *ppLines = pLines;
  84.     return NOERROR;
  85.     
  86. error: 
  87.     if (pLines == NULL)
  88.         return E_OUTOFMEMORY;
  89.     if (pLines->m_ptinfo)
  90.         pLines->m_ptinfo->Release();                            
  91.     if (pLines->m_psa) 
  92.         SafeArrayDestroy(pLines->m_psa); 
  93.   
  94.     pLines->m_psa = NULL;
  95.     pLines->m_ptinfo = NULL; 
  96.     
  97.     delete pLines;
  98.     return hr;
  99. }
  100.  
  101. /*
  102.  * CLines::CLines
  103.  *
  104.  * Purpose:
  105.  *  Constructor for CLines object. Initializes members to NULL.
  106.  *
  107.  */
  108. #pragma warning (disable : 4355)
  109. CLines::CLines() : m_SupportErrorInfo(this, IID_ILines)
  110. #pragma warning (default : 4355)
  111. {    
  112.     m_cRef = 0;
  113.     m_psa = NULL;
  114.     m_ptinfo = NULL; 
  115. }
  116.  
  117. /*
  118.  * CLines::~CLines
  119.  *
  120.  * Purpose:
  121.  *  Destructor for CLines object. 
  122.  *
  123.  */
  124. CLines::~CLines()
  125. {    
  126.      if (m_ptinfo) m_ptinfo->Release();                   
  127.      if (m_psa) SafeArrayDestroy(m_psa);
  128. }
  129.  
  130. /*
  131.  * CLines::QueryInterface, AddRef, Release
  132.  *
  133.  * Purpose:
  134.  *  Implements IUnknown::QueryInterface, AddRef, Release
  135.  *
  136.  */
  137. STDMETHODIMP
  138. CLines::QueryInterface(REFIID iid, void FAR* FAR* ppv) 
  139. {    
  140.     *ppv = NULL;
  141.         
  142.     if (iid == IID_IUnknown || iid == IID_ILines || 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. CLines::AddRef(void)
  155.  
  156. #ifdef _DEBUG  
  157.     TCHAR ach[50];
  158.     wsprintf(ach, TEXT("Ref = %ld, Lines\r\n"), m_cRef+1); 
  159.     OutputDebugString(ach); 
  160. #endif  
  161.     
  162.     return ++m_cRef;
  163. }
  164.  
  165.  
  166. STDMETHODIMP_(ULONG)
  167. CLines::Release(void)
  168.  
  169. #ifdef _DEBUG  
  170.     TCHAR ach[50];
  171.     wsprintf(ach, TEXT("Ref = %ld, Lines\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.  * CLines::GetTypeInfoCount
  184.  *
  185.  * Purpose:
  186.  *  Implements IDispatch::GetTypeInfoCount.
  187.  *
  188.  */
  189. STDMETHODIMP
  190. CLines::GetTypeInfoCount(UINT FAR* pctinfo)
  191. {
  192.     *pctinfo = 1;
  193.     return NOERROR;
  194. }
  195.  
  196. /*
  197.  * CLines::GetTypeInfo
  198.  *
  199.  * Purpose:
  200.  *  Implements IDispatch::GetTypeInfo. 
  201.  *
  202.  */
  203. STDMETHODIMP
  204. CLines::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.  * CLines::GetIDsOfNames
  222.  *
  223.  * Purpose:
  224.  *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,
  225.  *  is used.
  226.  *
  227.  */
  228. STDMETHODIMP 
  229. CLines::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.  * CLines::Invoke
  241.  *
  242.  * Purpose:
  243.  *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,
  244.  *  is used.
  245.  *
  246.  */
  247. STDMETHODIMP
  248. CLines::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.  * 
  266.  * Properties and methods exposed through automation.
  267.  *
  268.  */
  269.  
  270. /*
  271.  * CLines::Add
  272.  *
  273.  * Purpose:
  274.  *  Adds a line to the lines collection. 
  275.  *
  276.  * Parameters:
  277.  *  pLineNew    IDispatch of line to be added to collection.
  278.  *
  279.  */
  280. STDMETHODIMP  
  281. CLines::Add(ILine FAR* pLineNew)
  282.     HRESULT hr;   
  283.     LONG l;
  284.     CLine FAR* pLine = NULL;
  285.     VARIANT v;       
  286.     HDC hdc;
  287.     
  288.     // Is the collection full?
  289.     if (m_cElements == m_cMax) 
  290.         return RaiseException(IDS_CollectionFull, IID_ILines);
  291.  
  292.     hr = pLineNew->QueryInterface(IID_ILine, (void FAR* FAR*)&pLine);
  293.     if (FAILED(hr))
  294.         return RaiseException(IDS_LineFromOtherInstance, IID_ILines);
  295.     
  296.     // Add end points of line to the pane's point collection    
  297.     if (FALSE == pLine->AddEndPointsToPane(m_pPane))     
  298.         {hr = RaiseException(IDS_CantAddEndPoints, IID_ILines); goto error;}  
  299.     
  300.     // Add new line to collection
  301.     l = m_lLBound+m_cElements; 
  302.     VariantInit(&v);
  303.     V_VT(&v) = VT_DISPATCH;
  304.     V_DISPATCH(&v) = pLineNew;    
  305.     hr = SafeArrayPutElement(m_psa, &l, &v);
  306.     if (FAILED(hr))
  307.         {hr = RaiseException(IDS_Unexpected, IID_ILines); goto error;}  
  308.     m_cElements++;   
  309.     
  310.     // Draw the new line
  311.     hdc = m_pPane->GetDC();    
  312.     pLine->Draw(hdc);
  313.     m_pPane->ReleaseDC(hdc);  
  314.     
  315.     pLine->Release();                    
  316.     return NOERROR;    
  317.     
  318. error:  
  319.     if (pLine)
  320.         pLine->Release();      
  321.     return hr;   
  322. }
  323.  
  324. /*
  325.  * CLines::get_Count
  326.  *
  327.  * Purpose:
  328.  *  Returns number of items in collection.
  329.  *
  330.  */
  331. STDMETHODIMP    
  332. CLines::get_Count(long FAR* lCount)  
  333. {
  334.     *lCount = m_cElements;
  335.     return NOERROR;             
  336. }
  337.  
  338. /*
  339.  * CLines::get_Item
  340.  *
  341.  * Purpose:
  342.  *  Retrieves item from collection, given an index. 
  343.  *
  344.  * Parameters:   
  345.  *   lIndex   Index of item to be retrieved. 
  346.  *   ppLine   Returns IDispatch of item retrieved from collection.
  347.  *
  348.  */
  349. STDMETHODIMP
  350. CLines::get_Item(long lIndex, ILine FAR* FAR* ppLine)
  351.     HRESULT hr;                                            
  352.     VARIANT v;
  353.    
  354.     // Check if index is within range         
  355.     if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements)) 
  356.         return RaiseException(IDS_InvalidIndex, IID_ILines); 
  357.     
  358.     // Retrieve and return item. Note that SafeArrayGetElement AddRefs, so an additional AddRef
  359.     // is not required.
  360.     VariantInit(&v);
  361.     hr = SafeArrayGetElement(m_psa, &lIndex, &v);
  362.     if (FAILED(hr))
  363.         return RaiseException(IDS_Unexpected, IID_ILines);
  364.     *ppLine = (ILine FAR*) V_DISPATCH(&v);  
  365.     return NOERROR;
  366. }
  367.  
  368. /*
  369.  * CLines::get_NewEnum
  370.  *
  371.  * Purpose:
  372.  *  Returns an enumerator (IEnumVARIANT) for the items curently in the collection. 
  373.  *  The NewEnum property is restricted and so is invisible to users of an 
  374.  *  automation controller's scripting language. Automation controllers that support
  375.  *  a 'For Each' statement to iterate through the elements of a collection will use
  376.  *  the enumerator returned by NewEnum. The enumerator creates a snapshot of the
  377.  *  the current state of the collection.
  378.  *
  379.  */
  380. STDMETHODIMP
  381. CLines::get__NewEnum(IUnknown FAR* FAR* ppunkEnum)
  382. {
  383.     CEnumVariant FAR* penum = NULL;;
  384.     HRESULT hr;
  385.     
  386.     *ppunkEnum = NULL;
  387.     
  388.     // Create new enumerator for items currently in collection and QI for IUnknown
  389.     hr = CEnumVariant::Create(m_psa, m_cElements, &penum);
  390.     if (FAILED(hr))
  391.         {hr = RaiseException(IDS_OutOfMemory, IID_ILines); goto error;}        
  392.     hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)ppunkEnum);    
  393.     if (FAILED(hr)) 
  394.         {hr = RaiseException(IDS_Unexpected, IID_ILines); goto error;}  
  395.     return NOERROR; 
  396.     
  397. error:
  398.     if (penum)
  399.         delete penum;   
  400.     return hr;              
  401. }
  402.  
  403. /*
  404.  * CLines::Remove
  405.  *
  406.  * Purpose:
  407.  *  Removes specified item from collection. 
  408.  *
  409.  * Parameters:   
  410.  *   lIndex   Index of item to be removed. 
  411.  *
  412.  */
  413. STDMETHODIMP
  414. CLines::Remove(long lIndex)
  415. {
  416.     HRESULT hr;
  417.     long l;
  418.     VARIANT HUGEP *pvar;
  419.     CLine FAR* pLine = NULL;  
  420.     RECT rc;
  421.     
  422.     // Check if integer index is within range. 
  423.     if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements))
  424.         return RaiseException(IDS_InvalidIndex, IID_ILines);    
  425.  
  426.     hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);
  427.     if (FAILED(hr))
  428.         return RaiseException(IDS_Unexpected, IID_ILines); 
  429.     V_DISPATCH(&pvar[lIndex-m_lLBound])->QueryInterface(IID_ILine, (void FAR* FAR*)&pLine);         
  430.      
  431.     // Ask the pane to invalidate the area where the line is drawn.
  432.     pLine->GetInvalidateRect(&rc);
  433.     m_pPane->InvalidateRect(&rc);
  434.     
  435.     // Remove end points of line from the pane's point collection.   
  436.     pLine->RemoveEndPointsFromPane(m_pPane);    
  437.     // Remove Line  
  438.     V_DISPATCH(&pvar[lIndex-m_lLBound])->Release();    
  439.     // Move up the array elements, after the element to be removed.        
  440.     for (l=lIndex-m_lLBound; l<(long)(m_cElements-1); l++)  
  441.         pvar[l] = pvar[l+1];    
  442.     // Remove last element.    
  443.     V_VT(&pvar[l]) = VT_EMPTY;
  444.     
  445.     pLine->Release();        
  446.     hr = SafeArrayUnaccessData(m_psa);
  447.     if (FAILED(hr))
  448.        return RaiseException(IDS_Unexpected, IID_ILines); 
  449.        
  450.     m_cElements--;  
  451.     m_pPane->Update();     // Ask the pane to repaint invalidated areas caused by removal of line.
  452.     return NOERROR;
  453. }
  454.  
  455. /* 
  456.  *
  457.  * The following methods are not exposed through Automation
  458.  *
  459.  */  
  460.  
  461. /*
  462.  * CLines::Draw
  463.  *
  464.  * Purpose:
  465.  *  Draws all lines in collection.
  466.  *
  467.  */
  468. STDMETHODIMP_(void)
  469. CLines::Draw(HDC hdc)
  470. {
  471.     HRESULT hr;
  472.     long l;
  473.     CLine FAR* pLine = NULL;
  474.     VARIANT HUGEP *pvar;
  475.     
  476.     // Draw each line in the Lines collection
  477.     hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);
  478.     if (FAILED(hr))
  479.        return;           
  480.     for (l=0; l<(long)m_cElements; l++)
  481.     {        
  482.         hr = V_DISPATCH(&pvar[l])->QueryInterface(IID_ILine, (void FAR* FAR*)&pLine);
  483.         if (FAILED(hr))
  484.             continue;          
  485.         pLine->Draw(hdc);
  486.         pLine->Release();        
  487.     }   
  488.     hr = SafeArrayUnaccessData(m_psa);
  489.     if (FAILED(hr))
  490.         return;
  491.     return;
  492. }
  493.  
  494. /*
  495.  * CLines::Clear
  496.  *
  497.  * Purpose:
  498.  *  Removes all items from collection.
  499.  *
  500.  */
  501. STDMETHODIMP_(void)
  502. CLines::Clear(void)
  503. {
  504.     SafeArrayDestroyData(m_psa);   
  505.     SafeArrayAllocData(m_psa);
  506.     m_cElements = 0;
  507. }
  508.  
  509.