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 / chap04 / connect / connpt.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  12KB  |  512 lines

  1. /*
  2.  * CONNPT.CPP
  3.  *
  4.  * Implemenation of a connection point object that manages
  5.  * IUnknown pointers.  This is a stand-alone object created from
  6.  * the implementation of IConnectionPointContainer.
  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 "connect.h"
  17.  
  18.  
  19. /*
  20.  * CConnectionPoint::CConnectionPoint
  21.  * CConnectionPoint::~CConnectionPoint
  22.  *
  23.  * Parameters (Constructor):
  24.  *  pObj            PCConnObject of the object we're in.  We can
  25.  *                  query this for the IConnectionPointContainer
  26.  *                  interface we might need.
  27.  *  riid            REFIID of the interface we're supporting
  28.  */
  29.  
  30. CConnectionPoint::CConnectionPoint(PCConnObject pObj, REFIID riid)
  31.     {
  32.     UINT        i;
  33.  
  34.     m_cRef=0;
  35.     m_iid=riid;
  36.  
  37.     /*
  38.      * Our lifetime is controlled by the connectable object itself,
  39.      * although other external clients will call AddRef and Release.
  40.      * Since we're nested in the connectable object's lifetime,
  41.      * there's no need to call AddRef on pObj.
  42.      */
  43.     m_pObj=pObj;
  44.  
  45.     for (i=0; i < CCONNMAX; i++)
  46.         {
  47.         m_rgpIUnknown[i]=NULL;
  48.         m_rgdwCookies[i]=0;
  49.         }
  50.  
  51.     m_cConn=0;
  52.     m_dwCookieNext=100;       //Arbitrary starting cookie value
  53.     return;
  54.     }
  55.  
  56. CConnectionPoint::~CConnectionPoint(void)
  57.     {
  58.     UINT        i;
  59.  
  60.     for (i=0; i < CCONNMAX; i++)
  61.         ReleaseInterface(m_rgpIUnknown[i]);
  62.  
  63.     return;
  64.     }
  65.  
  66.  
  67.  
  68. /*
  69.  * CConnectionPoint::QueryInterface
  70.  * CConnectionPoint::AddRef
  71.  * CConnectionPoint::Release
  72.  *
  73.  * Purpose:
  74.  *  Non-delegating IUnknown members for CConnectionPoint.
  75.  */
  76.  
  77. STDMETHODIMP CConnectionPoint::QueryInterface(REFIID riid
  78.     , LPVOID *ppv)
  79.     {
  80.     *ppv=NULL;
  81.  
  82.     if (IID_IUnknown==riid || IID_IConnectionPoint==riid)
  83.         *ppv=(LPVOID)this;
  84.  
  85.     if (NULL!=*ppv)
  86.         {
  87.         ((LPUNKNOWN)*ppv)->AddRef();
  88.         return NOERROR;
  89.         }
  90.  
  91.     return ResultFromScode(E_NOINTERFACE);
  92.     }
  93.  
  94. STDMETHODIMP_(ULONG) CConnectionPoint::AddRef(void)
  95.     {
  96.     return ++m_cRef;
  97.     }
  98.  
  99. STDMETHODIMP_(ULONG) CConnectionPoint::Release(void)
  100.     {
  101.     if (0!=--m_cRef)
  102.         return m_cRef;
  103.  
  104.     delete this;
  105.     return 0;
  106.     }
  107.  
  108.  
  109.  
  110. /*
  111.  * CConnectionPoint::GetConnectionInterface
  112.  *
  113.  * Purpose:
  114.  *  Returns the IID of the outgoing interface supported through
  115.  *  this connection point.
  116.  *
  117.  * Parameters:
  118.  *  pIID            IID * in which to store the IID.
  119.  */
  120.  
  121. STDMETHODIMP CConnectionPoint::GetConnectionInterface(IID *pIID)
  122.     {
  123.     if (NULL==pIID)
  124.         return ResultFromScode(E_POINTER);
  125.  
  126.     *pIID=m_iid;
  127.     return NOERROR;
  128.     }
  129.  
  130.  
  131.  
  132. /*
  133.  * CConnectionPoint::GetConnectionPointContainer
  134.  *
  135.  * Purpose:
  136.  *  Returns a pointer to the IConnectionPointContainer that
  137.  *  is manageing this connection point.
  138.  *
  139.  * Parameters:
  140.  *  ppCPC           IConnectionPointContainer ** in which to return
  141.  *                  the pointer after calling AddRef.
  142.  */
  143.  
  144. STDMETHODIMP CConnectionPoint::GetConnectionPointContainer
  145.     (IConnectionPointContainer **ppCPC)
  146.     {
  147.     return m_pObj->QueryInterface(IID_IConnectionPointContainer
  148.         , (void **)ppCPC);
  149.     }
  150.  
  151.  
  152.  
  153. /*
  154.  * CConnectionPoint::Advise
  155.  *
  156.  * Purpose:
  157.  *  Provides this connection point with a notification sink to
  158.  *  call whenever the appropriate outgoing function/event occurs.
  159.  *
  160.  * Parameters:
  161.  *  pUnkSink        LPUNKNOWN to the sink to notify.  The connection
  162.  *                  point must QueryInterface on this pointer to obtain
  163.  *                  the proper interface to call.  The connection
  164.  *                  point must also insure that any pointer held has
  165.  *                  a reference count (QueryInterface will do it).
  166.  *  pdwCookie       DWORD * in which to store the connection key for
  167.  *                  later calls to Unadvise.
  168.  */
  169.  
  170. STDMETHODIMP CConnectionPoint::Advise(LPUNKNOWN pUnkSink
  171.     , DWORD *pdwCookie)
  172.     {
  173.     UINT            i;
  174.     IUnknown       *pSink;
  175.  
  176.     *pdwCookie=0;
  177.  
  178.     //Check if we're already full of sink pointers
  179.     if (CCONNMAX==m_cConn)
  180.         return ResultFromScode(CONNECT_E_ADVISELIMIT);
  181.  
  182.     /*
  183.      * Verify that the sink has the interface it's supposed
  184.      * to.  We don't have to know what it is because we have
  185.      * m_iid to describe it.  If this works, then we neatly
  186.      * have a pointer with an AddRef that we can stow away.
  187.      */
  188.     if (FAILED(pUnkSink->QueryInterface(m_iid, (PPVOID)&pSink)))
  189.         return ResultFromScode(CONNECT_E_CANNOTCONNECT);
  190.  
  191.     /*
  192.      * We got the sink, now store it in our array.  We'll look for
  193.      * the first entry that is NULL, indicating a free spot.
  194.      */
  195.     for (i=0; i < CCONNMAX; i++)
  196.         {
  197.         if (NULL==m_rgpIUnknown[i])
  198.             {
  199.             m_rgpIUnknown[i]=pSink;
  200.  
  201.             /*
  202.              * Note:  this increment is not thread safe.  Needs
  203.              * to be blocked with a semaphore if this were a
  204.              * multi-threaded object.
  205.              */
  206.             m_rgdwCookies[i]=++m_dwCookieNext;
  207.             *pdwCookie=m_dwCookieNext;
  208.             break;
  209.             }
  210.         }
  211.  
  212.     m_cConn++;
  213.     return NOERROR;
  214.     }
  215.  
  216.  
  217.  
  218. /*
  219.  * CConnectionPoint::Unadvise
  220.  *
  221.  * Purpose:
  222.  *  Terminates the connection to the notification sink identified
  223.  *  with dwCookie (that was returned from Advise).  The connection
  224.  *  point has to Release any held pointers for that sink.
  225.  *
  226.  * Parameters:
  227.  *  dwCookie        DWORD connection key from Advise.
  228.  */
  229.  
  230. STDMETHODIMP CConnectionPoint::Unadvise(DWORD dwCookie)
  231.     {
  232.     UINT        i;
  233.  
  234.     if (0==dwCookie)
  235.         return ResultFromScode(E_INVALIDARG);
  236.  
  237.     for (i=0; i < CCONNMAX; i++)
  238.         {
  239.         if (dwCookie==m_rgdwCookies[i])
  240.             {
  241.             //This releases the sink and sets the pointer to NULL
  242.             ReleaseInterface(m_rgpIUnknown[i]);
  243.             m_rgdwCookies[i]=0;
  244.             m_cConn--;
  245.             return NOERROR;
  246.             }
  247.         }
  248.  
  249.     return ResultFromScode(CONNECT_E_NOCONNECTION);
  250.     }
  251.  
  252.  
  253.  
  254. /*
  255.  * CConnectionPoint::EnumConnections
  256.  *
  257.  * Purpose:
  258.  *  Creates and returns an enumerator object with the
  259.  *  IEnumConnections interface that will enumerate the IUnknown
  260.  *  pointers of each connected sink.
  261.  *
  262.  * Parameters:
  263.  *  ppEnum          LPENUMCONNECTIONS in which to store the
  264.  *                  IEnumConnections pointer.
  265.  */
  266.  
  267. STDMETHODIMP CConnectionPoint::EnumConnections
  268.     (LPENUMCONNECTIONS *ppEnum)
  269.     {
  270.     LPCONNECTDATA       pCD;
  271.     UINT                i, j;
  272.     PCEnumConnections   pEnum;
  273.  
  274.     *ppEnum=NULL;
  275.  
  276.     if (0==m_cConn)
  277.         return ResultFromScode(OLE_E_NOCONNECTION);
  278.  
  279.     /*
  280.      * Create the array of CONNECTDATA structures to give to the
  281.      * enumerator.
  282.      */
  283.     pCD=new CONNECTDATA[(UINT)m_cConn];
  284.  
  285.     if (NULL==pCD)
  286.         return ResultFromScode(E_OUTOFMEMORY);
  287.  
  288.     for (i=0, j=0; i < CCONNMAX; i++)
  289.         {
  290.         if (NULL!=m_rgpIUnknown[i])
  291.             {
  292.             pCD[j].pUnk=(LPUNKNOWN)m_rgpIUnknown[i];
  293.             pCD[j].dwCookie=m_rgdwCookies[i];
  294.             j++;
  295.             }
  296.         }
  297.  
  298.     /*
  299.      * If creation works, it makes a copy pCD, so we can
  300.      * always delete it regardless of the outcome.
  301.      */
  302.     pEnum=new CEnumConnections(this, m_cConn, pCD);
  303.     delete [] pCD;
  304.  
  305.     if (NULL==pEnum)
  306.         return ResultFromScode(E_OUTOFMEMORY);
  307.  
  308.     //This does an AddRef for us.
  309.     return pEnum->QueryInterface(IID_IEnumConnections, (PPVOID)ppEnum);
  310.     }
  311.  
  312.  
  313.  
  314.  
  315. //Connection Enumerator follows
  316.  
  317.  
  318. /*
  319.  * CEnumConnections::CEnumConnections
  320.  * CEnumConnections::~CEnumConnections
  321.  *
  322.  * Parameters (Constructor):
  323.  *  pUnkRef         LPUNKNOWN to use for reference counting.
  324.  *  cConn           ULONG number of connections in prgpConn
  325.  *  prgConnData     LPCONNECTDATA to the array to enumerate.
  326.  */
  327.  
  328. CEnumConnections::CEnumConnections(LPUNKNOWN pUnkRef, ULONG cConn
  329.     , LPCONNECTDATA prgConnData)
  330.     {
  331.     UINT        i;
  332.  
  333.     m_cRef=0;
  334.     m_pUnkRef=pUnkRef;
  335.  
  336.     m_iCur=0;
  337.     m_cConn=cConn;
  338.  
  339.     /*
  340.      * Copy the passed array.  We need to do this because a clone
  341.      * has to have its own copy as well.
  342.      */
  343.     m_rgConnData=new CONNECTDATA[(UINT)cConn];
  344.  
  345.     if (NULL!=m_rgConnData)
  346.         {
  347.         for (i=0; i < cConn; i++)
  348.             {
  349.             m_rgConnData[i]=prgConnData[i];
  350.             m_rgConnData[i].pUnk->AddRef();
  351.             }
  352.         }
  353.  
  354.     return;
  355.     }
  356.  
  357.  
  358. CEnumConnections::~CEnumConnections(void)
  359.     {
  360.     if (NULL!=m_rgConnData)
  361.         {
  362.         UINT        i;
  363.  
  364.         for (i=0; i < m_cConn; i++)
  365.             m_rgConnData[i].pUnk->Release();
  366.  
  367.         delete [] m_rgConnData;
  368.         }
  369.  
  370.     return;
  371.     }
  372.  
  373.  
  374.  
  375.  
  376. /*
  377.  * CEnumConnections::QueryInterface
  378.  * CEnumConnections::AddRef
  379.  * CEnumConnections::Release
  380.  *
  381.  * Purpose:
  382.  *  IUnknown members for CEnumConnections object.
  383.  */
  384.  
  385. STDMETHODIMP CEnumConnections::QueryInterface(REFIID riid
  386.     , LPVOID *ppv)
  387.     {
  388.     *ppv=NULL;
  389.  
  390.     if (IID_IUnknown==riid || IID_IEnumConnections==riid)
  391.         *ppv=(LPVOID)this;
  392.  
  393.     if (NULL!=*ppv)
  394.         {
  395.         ((LPUNKNOWN)*ppv)->AddRef();
  396.         return NOERROR;
  397.         }
  398.  
  399.     return ResultFromScode(E_NOINTERFACE);
  400.     }
  401.  
  402.  
  403. STDMETHODIMP_(ULONG) CEnumConnections::AddRef(void)
  404.     {
  405.     ++m_cRef;
  406.     m_pUnkRef->AddRef();
  407.     return m_cRef;
  408.     }
  409.  
  410. STDMETHODIMP_(ULONG) CEnumConnections::Release(void)
  411.     {
  412.     m_pUnkRef->Release();
  413.  
  414.     if (0L!=--m_cRef)
  415.         return m_cRef;
  416.  
  417.     delete this;
  418.     return 0;
  419.     }
  420.  
  421.  
  422.  
  423.  
  424.  
  425. /*
  426.  * CEnumConnections::Next
  427.  *
  428.  * Purpose:
  429.  *  Returns the next element in the enumeration.
  430.  *
  431.  * Parameters:
  432.  *  cConn           ULONG number of connections to return.
  433.  *  pConnData       LPCONNECTDATA in which to store the returned
  434.  *                  structures.
  435.  *  pulEnum         ULONG * in which to return how many we
  436.  *                  enumerated.
  437.  *
  438.  * Return Value:
  439.  *  HRESULT         NOERROR if successful, S_FALSE otherwise,
  440.  */
  441.  
  442. STDMETHODIMP CEnumConnections::Next(ULONG cConn
  443.     , LPCONNECTDATA pConnData, ULONG *pulEnum)
  444.     {
  445.     ULONG               cReturn=0L;
  446.  
  447.     if (NULL==m_rgConnData)
  448.         return ResultFromScode(S_FALSE);
  449.  
  450.     if (NULL==pulEnum)
  451.         {
  452.         if (1L!=cConn)
  453.             return ResultFromScode(E_POINTER);
  454.         }
  455.     else
  456.         *pulEnum=0L;
  457.  
  458.     if (NULL==pConnData || m_iCur >= m_cConn)
  459.         return ResultFromScode(S_FALSE);
  460.  
  461.     while (m_iCur < m_cConn && cConn > 0)
  462.         {
  463.         *pConnData++=m_rgConnData[m_iCur];
  464.         m_rgConnData[m_iCur++].pUnk->AddRef();
  465.         cReturn++;
  466.         cConn--;
  467.         }
  468.  
  469.     if (NULL!=pulEnum)
  470.         *pulEnum=cReturn;
  471.  
  472.     return NOERROR;
  473.     }
  474.  
  475.  
  476.  
  477. STDMETHODIMP CEnumConnections::Skip(ULONG cSkip)
  478.     {
  479.     if (((m_iCur+cSkip) >= m_cConn) || NULL==m_rgConnData)
  480.         return ResultFromScode(S_FALSE);
  481.  
  482.     m_iCur+=cSkip;
  483.     return NOERROR;
  484.     }
  485.  
  486.  
  487. STDMETHODIMP CEnumConnections::Reset(void)
  488.     {
  489.     m_iCur=0;
  490.     return NOERROR;
  491.     }
  492.  
  493.  
  494. STDMETHODIMP CEnumConnections::Clone(LPENUMCONNECTIONS *ppEnum)
  495.     {
  496.     PCEnumConnections   pNew;
  497.  
  498.     *ppEnum=NULL;
  499.  
  500.     //Create the clone
  501.     pNew=new CEnumConnections(m_pUnkRef, m_cConn, m_rgConnData);
  502.  
  503.     if (NULL==pNew)
  504.         return ResultFromScode(E_OUTOFMEMORY);
  505.  
  506.     pNew->AddRef();
  507.     pNew->m_iCur=m_iCur;
  508.  
  509.     *ppEnum=pNew;
  510.     return NOERROR;
  511.     }
  512.