home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLECONN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  15.8 KB  |  686 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFXCTL_CORE3_SEG
  14. #pragma code_seg(AFXCTL_CORE3_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24.  
  25. #define GetConnectionPtr(pTarget, pEntry) \
  26.     (LPCONNECTIONPOINT)((char*)pTarget + pEntry->nOffset + \
  27.             offsetof(CConnectionPoint, m_xConnPt))
  28.  
  29.  
  30. /////////////////////////////////////////////////////////////////////////////
  31. // CConnectionPoint
  32.  
  33. CConnectionPoint::CConnectionPoint() :
  34.     m_pUnkFirstConnection(NULL),
  35.     m_pConnections(NULL)
  36. {
  37. }
  38.  
  39. CConnectionPoint::~CConnectionPoint()
  40. {
  41.     POSITION pos = GetStartPosition();
  42.     while (pos != NULL)
  43.     {
  44.         LPUNKNOWN pUnk = GetNextConnection(pos);
  45.         ASSERT(pUnk != NULL);
  46.         pUnk->Release();
  47.     }
  48.  
  49.     if (m_pConnections != NULL)
  50.         delete m_pConnections;
  51. }
  52.  
  53. POSITION CConnectionPoint::GetStartPosition() const
  54. {
  55.     ASSERT(m_pConnections == NULL || m_pUnkFirstConnection == NULL);
  56.  
  57.     if (m_pUnkFirstConnection != NULL)
  58.         return (POSITION)-1;
  59.  
  60.     if (m_pConnections == NULL || m_pConnections->GetSize() == 0)
  61.         return NULL;
  62.  
  63.     return (POSITION)1;
  64. }
  65.  
  66. LPUNKNOWN CConnectionPoint::GetNextConnection(POSITION& pos) const
  67. {
  68.     ASSERT(pos != NULL);
  69.  
  70.     if (pos == (POSITION)-1)
  71.     {
  72.         ASSERT(m_pUnkFirstConnection != NULL);
  73.         ASSERT(m_pConnections == NULL);
  74.  
  75.         pos = NULL;
  76.         return m_pUnkFirstConnection;
  77.     }
  78.  
  79.     ASSERT(m_pConnections != NULL);
  80.     ASSERT((long)pos > 0 && (long)pos <= m_pConnections->GetSize());
  81.  
  82.     int nIndex = (long)pos - 1;
  83.     pos = (POSITION)((long)pos + 1);
  84.     if ((long)pos > m_pConnections->GetSize())
  85.         pos = NULL;
  86.     return (LPUNKNOWN)m_pConnections->GetAt(nIndex);
  87. }
  88.  
  89. const CPtrArray* CConnectionPoint::GetConnections()
  90. {
  91.     ASSERT_VALID(this);
  92.     if (m_pConnections == NULL)
  93.         CreateConnectionArray();
  94.  
  95.     ASSERT(m_pConnections != NULL);
  96.     return m_pConnections;
  97. }
  98.  
  99. void CConnectionPoint::OnAdvise(BOOL)
  100. {
  101.     ASSERT_VALID(this);
  102. }
  103.  
  104. int CConnectionPoint::GetMaxConnections()
  105. {
  106.     ASSERT_VALID(this);
  107.  
  108.     // May be overridden by subclass.
  109.     return -1;
  110. }
  111.  
  112. LPCONNECTIONPOINTCONTAINER CConnectionPoint::GetContainer()
  113. {
  114.     CCmdTarget* pCmdTarget = (CCmdTarget*)((BYTE*)this - m_nOffset);
  115. #ifdef _DEBUG
  116.     pCmdTarget->CCmdTarget::AssertValid();
  117. #endif
  118.  
  119.     LPCONNECTIONPOINTCONTAINER pCPC = NULL;
  120.     if (SUCCEEDED((HRESULT)pCmdTarget->ExternalQueryInterface(
  121.             &IID_IConnectionPointContainer, (LPVOID*)&pCPC)))
  122.     {
  123.         ASSERT(pCPC != NULL);
  124.     }
  125.  
  126.     return pCPC;
  127. }
  128.  
  129. void CConnectionPoint::CreateConnectionArray()
  130. {
  131.     ASSERT(m_pConnections == NULL);
  132.  
  133.     m_pConnections = new CPtrArray;
  134.     if (m_pUnkFirstConnection != NULL)
  135.     {
  136.         m_pConnections->Add(m_pUnkFirstConnection);
  137.         m_pUnkFirstConnection = NULL;
  138.     }
  139.  
  140.     ASSERT(m_pConnections != NULL);
  141.     ASSERT(m_pUnkFirstConnection == NULL);
  142. }
  143.  
  144. int CConnectionPoint::GetConnectionCount()
  145. {
  146.     if (m_pUnkFirstConnection != NULL)
  147.         return 1;
  148.  
  149.     if (m_pConnections == NULL)
  150.         return 0;
  151.  
  152.     return m_pConnections->GetSize();
  153. }
  154.  
  155. LPUNKNOWN CConnectionPoint::QuerySinkInterface(LPUNKNOWN pUnkSink)
  156. {
  157.     LPUNKNOWN pUnkReturn = NULL;
  158.     pUnkSink->QueryInterface(GetIID(), reinterpret_cast<void**>(&pUnkReturn));
  159.     return pUnkReturn;
  160. }
  161.  
  162. STDMETHODIMP_(ULONG) CConnectionPoint::XConnPt::Release()
  163. {
  164.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  165.     return (ULONG)pThis->InternalRelease();
  166. }
  167.  
  168. STDMETHODIMP_(ULONG) CConnectionPoint::XConnPt::AddRef()
  169. {
  170.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  171.     return (ULONG)pThis->InternalAddRef();
  172. }
  173.  
  174. STDMETHODIMP CConnectionPoint::XConnPt::QueryInterface(
  175.     REFIID iid, LPVOID* ppvObj)
  176. {
  177.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  178.     ASSERT(AfxIsValidAddress(ppvObj, sizeof(LPVOID), FALSE));
  179.  
  180.     if (IsEqualIID(iid, IID_IUnknown) ||
  181.         IsEqualIID(iid, IID_IConnectionPoint))
  182.     {
  183.         *ppvObj = this;
  184.         AddRef();
  185.         return S_OK;
  186.     }
  187.  
  188.     return E_NOINTERFACE;
  189. }
  190.  
  191. STDMETHODIMP CConnectionPoint::XConnPt::GetConnectionInterface(IID* pIID)
  192. {
  193.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  194.     ASSERT(AfxIsValidAddress(pIID, sizeof(IID)));
  195.  
  196.     *pIID = pThis->GetIID();
  197.     return S_OK;
  198. }
  199.  
  200. STDMETHODIMP CConnectionPoint::XConnPt::GetConnectionPointContainer(
  201.     IConnectionPointContainer** ppCPC)
  202. {
  203.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  204.     ASSERT(AfxIsValidAddress(ppCPC, sizeof(LPCONNECTIONPOINT)));
  205.  
  206.     if ((*ppCPC = pThis->GetContainer()) != NULL)
  207.         return S_OK;
  208.  
  209.     return E_FAIL;
  210. }
  211.  
  212. STDMETHODIMP CConnectionPoint::XConnPt::Advise(
  213.     LPUNKNOWN pUnkSink, DWORD* pdwCookie)
  214. {
  215.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  216.     ASSERT(AfxIsValidAddress(pUnkSink, sizeof(IUnknown), FALSE));
  217.     ASSERT((pdwCookie == NULL) || AfxIsValidAddress(pdwCookie, sizeof(DWORD)));
  218.  
  219.     if (pUnkSink == NULL)
  220.         return E_POINTER;
  221.  
  222.     LPUNKNOWN lpInterface;
  223.  
  224.     int cMaxConn = pThis->GetMaxConnections();
  225.     if ((cMaxConn >= 0) && (pThis->GetConnectionCount() == cMaxConn))
  226.     {
  227.         return CONNECT_E_ADVISELIMIT;
  228.     }
  229.  
  230.     if ((lpInterface = pThis->QuerySinkInterface(pUnkSink)) != NULL)
  231.     {
  232.         if (pThis->m_pUnkFirstConnection == NULL &&
  233.             pThis->m_pConnections == NULL)
  234.         {
  235.             pThis->m_pUnkFirstConnection = lpInterface;
  236.         }
  237.         else
  238.         {
  239.             if (pThis->m_pConnections == NULL)
  240.                 pThis->CreateConnectionArray();
  241.  
  242.             pThis->m_pConnections->Add(lpInterface);
  243.         }
  244.  
  245.         pThis->OnAdvise(TRUE);
  246.         if (pdwCookie != NULL)
  247.             *pdwCookie = (DWORD)lpInterface;
  248.         return S_OK;
  249.     }
  250.  
  251.     return E_NOINTERFACE;
  252. }
  253.  
  254. STDMETHODIMP CConnectionPoint::XConnPt::Unadvise(DWORD dwCookie)
  255. {
  256.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  257.  
  258.     if (pThis->m_pUnkFirstConnection != NULL)
  259.     {
  260.         if ((DWORD)pThis->m_pUnkFirstConnection == dwCookie)
  261.         {
  262.             pThis->m_pUnkFirstConnection->Release();
  263.             pThis->m_pUnkFirstConnection = NULL;
  264.             pThis->OnAdvise(FALSE);
  265.             return S_OK;
  266.         }
  267.         else
  268.         {
  269.             return CONNECT_E_NOCONNECTION;
  270.         }
  271.     }
  272.  
  273.     if (pThis->m_pConnections == NULL)
  274.         return CONNECT_E_NOCONNECTION;
  275.  
  276.     LPUNKNOWN pUnkSink;
  277.     int cConnections = pThis->m_pConnections->GetSize();
  278.     for (int i = 0; i < cConnections; i++)
  279.     {
  280.         pUnkSink = (LPUNKNOWN)(pThis->m_pConnections->GetAt(i));
  281.         if ((DWORD)pUnkSink == dwCookie)
  282.         {
  283.             pUnkSink->Release();
  284.             pThis->m_pConnections->RemoveAt(i);
  285.             pThis->OnAdvise(FALSE);
  286.             return S_OK;
  287.         }
  288.     }
  289.  
  290.     return CONNECT_E_NOCONNECTION;
  291. }
  292.  
  293. /////////////////////////////////////////////////////////////////////////////
  294. // CEnumConnections
  295.  
  296. class CEnumConnections : public CEnumArray
  297. {
  298. public:
  299.     CEnumConnections(const void* pvEnum, UINT nSize);
  300.     ~CEnumConnections();
  301.     void AddConnection(CONNECTDATA* pConn);
  302.  
  303. protected:
  304.     virtual BOOL OnNext(void* pv);
  305.     virtual CEnumArray* OnClone();
  306.  
  307.     UINT m_nMaxSize;    // number of items allocated (>= m_nSize)
  308.  
  309.     DECLARE_INTERFACE_MAP()
  310. };
  311.  
  312. BEGIN_INTERFACE_MAP(CEnumConnections, CEnumArray)
  313.     INTERFACE_PART(CEnumConnections, IID_IEnumConnections, EnumVOID)
  314. END_INTERFACE_MAP()
  315.  
  316.  
  317. CEnumConnections::CEnumConnections(const void* pvEnum, UINT nSize) :
  318.     CEnumArray(sizeof(CONNECTDATA), pvEnum, nSize, TRUE)
  319. {
  320.     m_nMaxSize = 0;
  321. }
  322.  
  323. CEnumConnections::~CEnumConnections()
  324. {
  325.     if (m_pClonedFrom == NULL)
  326.     {
  327.         UINT iCP;
  328.         CONNECTDATA* ppCP = (CONNECTDATA*)(VOID *)m_pvEnum;
  329.         for (iCP = 0; iCP < m_nSize; iCP++)
  330.             RELEASE(ppCP[iCP].pUnk);
  331.     }
  332.     // destructor will free the actual array (if it was not a clone)
  333. }
  334.  
  335. BOOL CEnumConnections::OnNext(void* pv)
  336. {
  337.     if (!CEnumArray::OnNext(pv))
  338.         return FALSE;
  339.  
  340.     // outgoing connection point needs to be AddRef'ed
  341.     //  (the caller has responsibility to release it)
  342.  
  343.     ((CONNECTDATA*)pv)->pUnk->AddRef();
  344.     return TRUE;
  345. }
  346.  
  347. CEnumArray* CEnumConnections::OnClone()
  348. {
  349.     ASSERT_VALID(this);
  350.     CEnumConnections* pClone;
  351.     pClone = new CEnumConnections(m_pvEnum, m_nSize);
  352.     pClone->m_bNeedFree = FALSE;
  353.     ASSERT(pClone != NULL);
  354.     ASSERT(!pClone->m_bNeedFree);   // clones should never free themselves
  355.     pClone->m_nCurPos = m_nCurPos;
  356.  
  357.     // finally, return the clone to OLE
  358.     ASSERT_VALID(pClone);
  359.     return pClone;
  360. }
  361.  
  362. void CEnumConnections::AddConnection(CONNECTDATA* pConn)
  363. {
  364.     ASSERT(m_nSize <= m_nMaxSize);
  365.  
  366.     if (m_nSize == m_nMaxSize)
  367.     {
  368.         // not enough space for new item -- allocate more
  369.         CONNECTDATA* pListNew = new CONNECTDATA[m_nSize+2];
  370.         m_nMaxSize += 2;
  371.         if (m_nSize > 0)
  372.             memcpy(pListNew, m_pvEnum, m_nSize*sizeof(CONNECTDATA));
  373.         delete m_pvEnum;
  374. #ifdef _WIN32
  375.         m_pvEnum = (BYTE*)pListNew;
  376. #else
  377.         m_pvEnum = (char*)pListNew;
  378. #endif
  379.     }
  380.  
  381.     // add this item to the list
  382.     ASSERT(m_nSize < m_nMaxSize);
  383.     ((CONNECTDATA*)m_pvEnum)[m_nSize] = *pConn;
  384.     pConn->pUnk->AddRef();
  385.     ++m_nSize;
  386. }
  387.  
  388. STDMETHODIMP CConnectionPoint::XConnPt::EnumConnections(LPENUMCONNECTIONS* ppEnum)
  389. {
  390.     METHOD_PROLOGUE_EX(CConnectionPoint, ConnPt)
  391.     CEnumConnections* pEnum = NULL;
  392.     CONNECTDATA cd;
  393.  
  394.     TRY
  395.     {
  396.         pEnum = new CEnumConnections(NULL, 0);
  397.  
  398.         if (pThis->m_pUnkFirstConnection != NULL)
  399.         {
  400.             cd.pUnk = pThis->m_pUnkFirstConnection;
  401.             cd.dwCookie = (DWORD)cd.pUnk;
  402.             pEnum->AddConnection(&cd);
  403.         }
  404.  
  405.         if (pThis->m_pConnections != NULL)
  406.         {
  407.             int cConnections = pThis->m_pConnections->GetSize();
  408.             for (int i = 0; i < cConnections; i++)
  409.             {
  410.                 cd.pUnk = (LPUNKNOWN)(pThis->m_pConnections->GetAt(i));
  411.                 cd.dwCookie = (DWORD)cd.pUnk;
  412.                 pEnum->AddConnection(&cd);
  413.             }
  414.         }
  415.     }
  416.     CATCH (CException, e)
  417.     {
  418.         delete pEnum;
  419.         pEnum = NULL;
  420.     }
  421.     END_CATCH
  422.  
  423.     if (pEnum != NULL)
  424.     {
  425.         // create and return the IEnumConnectionPoints object
  426.         *ppEnum = (IEnumConnections*)&pEnum->m_xEnumVOID;
  427.     }
  428.     else
  429.     {
  430.         // no connections: return NULL
  431.         *ppEnum = NULL;
  432.     }
  433.     return (pEnum != NULL) ? S_OK : E_OUTOFMEMORY;
  434. }
  435.  
  436.  
  437. /////////////////////////////////////////////////////////////////////////////
  438. // CEnumConnPoints
  439.  
  440. class CEnumConnPoints : public CEnumArray
  441. {
  442. public:
  443.     CEnumConnPoints(const void* pvEnum, UINT nSize);
  444.     ~CEnumConnPoints();
  445.     void AddConnPoint(LPCONNECTIONPOINT pConnPt);
  446.  
  447. protected:
  448.     virtual BOOL OnNext(void* pv);
  449.  
  450.     UINT m_nMaxSize;    // number of items allocated (>= m_nSize)
  451.  
  452.     DECLARE_INTERFACE_MAP()
  453. };
  454.  
  455. BEGIN_INTERFACE_MAP(CEnumConnPoints, CEnumArray)
  456.     INTERFACE_PART(CEnumConnPoints, IID_IEnumConnectionPoints, EnumVOID)
  457. END_INTERFACE_MAP()
  458.  
  459.  
  460. CEnumConnPoints::CEnumConnPoints(const void* pvEnum, UINT nSize) :
  461.     CEnumArray(sizeof(LPCONNECTIONPOINT), pvEnum, nSize, TRUE)
  462. {
  463.     m_nMaxSize = 0;
  464. }
  465.  
  466. CEnumConnPoints::~CEnumConnPoints()
  467. {
  468.     if (m_pClonedFrom == NULL)
  469.     {
  470.         UINT iCP;
  471.         LPCONNECTIONPOINT* ppCP =
  472.             (LPCONNECTIONPOINT*)(VOID *)m_pvEnum;
  473.         for (iCP = 0; iCP < m_nSize; iCP++)
  474.             RELEASE(ppCP[iCP]);
  475.     }
  476.     // destructor will free the actual array (if it was not a clone)
  477. }
  478.  
  479. BOOL CEnumConnPoints::OnNext(void* pv)
  480. {
  481.     if (!CEnumArray::OnNext(pv))
  482.         return FALSE;
  483.  
  484.     // outgoing connection point needs to be AddRef'ed
  485.     //  (the caller has responsibility to release it)
  486.  
  487.     (*(LPCONNECTIONPOINT*)pv)->AddRef();
  488.     return TRUE;
  489. }
  490.  
  491. void CEnumConnPoints::AddConnPoint(LPCONNECTIONPOINT pConnPt)
  492. {
  493.     ASSERT(m_nSize <= m_nMaxSize);
  494.  
  495.     if (m_nSize == m_nMaxSize)
  496.     {
  497.         // not enough space for new item -- allocate more
  498.         LPCONNECTIONPOINT* pListNew = new LPCONNECTIONPOINT[m_nSize+2];
  499.         m_nMaxSize += 2;
  500.         if (m_nSize > 0)
  501.             memcpy(pListNew, m_pvEnum, m_nSize*sizeof(LPCONNECTIONPOINT));
  502.         delete m_pvEnum;
  503. #ifdef _WIN32
  504.         m_pvEnum = (BYTE*)pListNew;
  505. #else
  506.         m_pvEnum = (char*)pListNew;
  507. #endif
  508.     }
  509.  
  510.     // add this item to the list
  511.     ASSERT(m_nSize < m_nMaxSize);
  512.     ((LPCONNECTIONPOINT*)m_pvEnum)[m_nSize] = pConnPt;
  513.     pConnPt->AddRef();
  514.     ++m_nSize;
  515. }
  516.  
  517.  
  518. /////////////////////////////////////////////////////////////////////////////
  519. // COleConnPtContainer
  520.  
  521. class COleConnPtContainer : public IConnectionPointContainer
  522. {
  523. public:
  524. #ifndef _AFX_NO_NESTED_DERIVATION
  525.     // required for METHOD_PROLOGUE_EX
  526.     size_t m_nOffset;
  527.     COleConnPtContainer::COleConnPtContainer()
  528.         { m_nOffset = offsetof(CCmdTarget, m_xConnPtContainer); }
  529. #endif
  530.  
  531.     STDMETHOD_(ULONG, AddRef)();
  532.     STDMETHOD_(ULONG, Release)();
  533.     STDMETHOD(QueryInterface)(REFIID, LPVOID*);
  534.  
  535.     STDMETHOD(EnumConnectionPoints)(LPENUMCONNECTIONPOINTS* ppEnum);
  536.     STDMETHOD(FindConnectionPoint)(REFIID iid, LPCONNECTIONPOINT* ppCP);
  537. };
  538.  
  539. STDMETHODIMP_(ULONG) COleConnPtContainer::AddRef()
  540. {
  541.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  542.     return (ULONG)pThis->ExternalAddRef();
  543. }
  544.  
  545. STDMETHODIMP_(ULONG) COleConnPtContainer::Release()
  546. {
  547.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  548.     return (ULONG)pThis->ExternalRelease();
  549. }
  550.  
  551. STDMETHODIMP COleConnPtContainer::QueryInterface(
  552.     REFIID iid, LPVOID* ppvObj)
  553. {
  554.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  555.     return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
  556. }
  557.  
  558. STDMETHODIMP COleConnPtContainer::EnumConnectionPoints(
  559.     LPENUMCONNECTIONPOINTS* ppEnum)
  560. {
  561.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  562.  
  563.     CEnumConnPoints* pEnum = NULL;
  564.  
  565.     TRY
  566.     {
  567.         pEnum = new CEnumConnPoints(NULL, 0);
  568.  
  569.         // Add connection points that aren't in the connection map
  570.         CPtrArray ptrArray;
  571.         if (pThis->GetExtraConnectionPoints(&ptrArray))
  572.         {
  573.             for (int i = 0; i < ptrArray.GetSize(); i++)
  574.                 pEnum->AddConnPoint((LPCONNECTIONPOINT)ptrArray.GetAt(i));
  575.         }
  576.  
  577.         // walk the chain of connection maps
  578.         const AFX_CONNECTIONMAP* pMap = pThis->GetConnectionMap();
  579.         const AFX_CONNECTIONMAP_ENTRY* pEntry;
  580.  
  581.         while (pMap != NULL)
  582.         {
  583.             pEntry = pMap->pEntry;
  584.  
  585.             while (pEntry->piid != NULL)
  586.             {
  587.                 pEnum->AddConnPoint(GetConnectionPtr(pThis, pEntry));
  588.                 ++pEntry;
  589.             }
  590. #ifdef _AFXDLL
  591.             pMap = (*pMap->pfnGetBaseMap)();
  592. #else
  593.             pMap = pMap->pBaseMap;
  594. #endif
  595.         }
  596.     }
  597.     CATCH (CException, e)
  598.     {
  599.         delete pEnum;
  600.         pEnum = NULL;
  601.     }
  602.     END_CATCH
  603.  
  604.     if (pEnum != NULL)
  605.     {
  606.         // create and return the IEnumConnectionPoints object
  607.         *ppEnum = (IEnumConnectionPoints*)&pEnum->m_xEnumVOID;
  608.     }
  609.     else
  610.     {
  611.         // no connection points: return NULL
  612.         *ppEnum = NULL;
  613.     }
  614.  
  615.     return (pEnum != NULL) ? S_OK : CONNECT_E_NOCONNECTION;
  616. }
  617.  
  618. STDMETHODIMP COleConnPtContainer::FindConnectionPoint(
  619.     REFIID iid, LPCONNECTIONPOINT* ppCP)
  620. {
  621.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  622.     ASSERT(ppCP != NULL);
  623.  
  624.     if ((*ppCP = pThis->GetConnectionHook(iid)) != NULL)
  625.     {
  626.         (*ppCP)->AddRef();
  627.         return S_OK;
  628.     }
  629.  
  630.     const AFX_CONNECTIONMAP* pMap = pThis->GetConnectionMap();
  631.     const AFX_CONNECTIONMAP_ENTRY* pEntry;
  632.  
  633.     while (pMap != NULL)
  634.     {
  635.         pEntry = pMap->pEntry;
  636.  
  637.         while (pEntry->piid != NULL)
  638.         {
  639.             if (IsEqualIID(iid, *(IID*)(pEntry->piid)))
  640.             {
  641.                 *ppCP = GetConnectionPtr(pThis, pEntry);
  642.                 (*ppCP)->AddRef();
  643.                 return S_OK;
  644.             }
  645.             ++pEntry;
  646.         }
  647. #ifdef _AFXDLL
  648.         pMap = (*pMap->pfnGetBaseMap)();
  649. #else
  650.         pMap = pMap->pBaseMap;
  651. #endif
  652.     }
  653.  
  654.     return E_NOINTERFACE;
  655. }
  656.  
  657.  
  658. /////////////////////////////////////////////////////////////////////////////
  659. // Wiring CCmdTarget to COleConnPtContainer
  660.  
  661. // enable this object for OLE connections, called from derived class ctor
  662. void CCmdTarget::EnableConnections()
  663. {
  664.     ASSERT(GetConnectionMap() != NULL);   // must have DECLARE_DISPATCH_MAP
  665.  
  666.     // construct an COleConnPtContainer instance just to get to the vtable
  667.     COleConnPtContainer cpc;
  668.  
  669.     // vtable pointer should be already set to same or NULL
  670.     ASSERT(m_xConnPtContainer.m_vtbl == NULL||
  671.         *(DWORD*)&cpc == m_xConnPtContainer.m_vtbl);
  672.     // verify that sizes match
  673.     ASSERT(sizeof(m_xConnPtContainer) == sizeof(COleConnPtContainer));
  674.  
  675.     // copy the vtable (and other data) to make sure it is initialized
  676.     m_xConnPtContainer.m_vtbl = *(DWORD*)&cpc;
  677.     *(COleConnPtContainer*)&m_xConnPtContainer = cpc;
  678. }
  679.  
  680. /////////////////////////////////////////////////////////////////////////////
  681. // Force any extra compiler-generated code into AFX_INIT_SEG
  682.  
  683. #ifdef AFX_INIT_SEG
  684. #pragma code_seg(AFX_INIT_SEG)
  685. #endif
  686.