home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / oleconn.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  16KB  |  687 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 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.  
  179.     ASSERT(AfxIsValidAddress(ppvObj, sizeof(LPVOID), FALSE));
  180.  
  181.     if (IsEqualIID(iid, IID_IUnknown) ||
  182.         IsEqualIID(iid, IID_IConnectionPoint))
  183.     {
  184.         *ppvObj = this;
  185.         AddRef();
  186.         return S_OK;
  187.     }
  188.  
  189.     return E_NOINTERFACE;
  190. }
  191.  
  192. STDMETHODIMP CConnectionPoint::XConnPt::GetConnectionInterface(IID* pIID)
  193. {
  194.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  195.     ASSERT(AfxIsValidAddress(pIID, sizeof(IID)));
  196.  
  197.     *pIID = pThis->GetIID();
  198.     return S_OK;
  199. }
  200.  
  201. STDMETHODIMP CConnectionPoint::XConnPt::GetConnectionPointContainer(
  202.     IConnectionPointContainer** ppCPC)
  203. {
  204.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  205.     ASSERT(AfxIsValidAddress(ppCPC, sizeof(LPCONNECTIONPOINT)));
  206.  
  207.     if ((*ppCPC = pThis->GetContainer()) != NULL)
  208.         return S_OK;
  209.  
  210.     return E_FAIL;
  211. }
  212.  
  213. STDMETHODIMP CConnectionPoint::XConnPt::Advise(
  214.     LPUNKNOWN pUnkSink, DWORD* pdwCookie)
  215. {
  216.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  217.     ASSERT(AfxIsValidAddress(pUnkSink, sizeof(IUnknown), FALSE));
  218.     ASSERT((pdwCookie == NULL) || AfxIsValidAddress(pdwCookie, sizeof(DWORD)));
  219.  
  220.     if (pUnkSink == NULL)
  221.         return E_POINTER;
  222.  
  223.     LPUNKNOWN lpInterface;
  224.  
  225.     int cMaxConn = pThis->GetMaxConnections();
  226.     if ((cMaxConn >= 0) && (pThis->GetConnectionCount() == cMaxConn))
  227.     {
  228.         return CONNECT_E_ADVISELIMIT;
  229.     }
  230.  
  231.     if ((lpInterface = pThis->QuerySinkInterface(pUnkSink)) != NULL)
  232.     {
  233.         if (pThis->m_pUnkFirstConnection == NULL &&
  234.             pThis->m_pConnections == NULL)
  235.         {
  236.             pThis->m_pUnkFirstConnection = lpInterface;
  237.         }
  238.         else
  239.         {
  240.             if (pThis->m_pConnections == NULL)
  241.                 pThis->CreateConnectionArray();
  242.  
  243.             pThis->m_pConnections->Add(lpInterface);
  244.         }
  245.  
  246.         pThis->OnAdvise(TRUE);
  247.         if (pdwCookie != NULL)
  248.             *pdwCookie = (DWORD)lpInterface;
  249.         return S_OK;
  250.     }
  251.  
  252.     return E_NOINTERFACE;
  253. }
  254.  
  255. STDMETHODIMP CConnectionPoint::XConnPt::Unadvise(DWORD dwCookie)
  256. {
  257.     METHOD_PROLOGUE_EX_(CConnectionPoint, ConnPt)
  258.  
  259.     if (pThis->m_pUnkFirstConnection != NULL)
  260.     {
  261.         if ((DWORD)pThis->m_pUnkFirstConnection == dwCookie)
  262.         {
  263.             pThis->m_pUnkFirstConnection->Release();
  264.             pThis->m_pUnkFirstConnection = NULL;
  265.             pThis->OnAdvise(FALSE);
  266.             return S_OK;
  267.         }
  268.         else
  269.         {
  270.             return CONNECT_E_NOCONNECTION;
  271.         }
  272.     }
  273.  
  274.     if (pThis->m_pConnections == NULL)
  275.         return CONNECT_E_NOCONNECTION;
  276.  
  277.     LPUNKNOWN pUnkSink;
  278.     int cConnections = pThis->m_pConnections->GetSize();
  279.     for (int i = 0; i < cConnections; i++)
  280.     {
  281.         pUnkSink = (LPUNKNOWN)(pThis->m_pConnections->GetAt(i));
  282.         if ((DWORD)pUnkSink == dwCookie)
  283.         {
  284.             pUnkSink->Release();
  285.             pThis->m_pConnections->RemoveAt(i);
  286.             pThis->OnAdvise(FALSE);
  287.             return S_OK;
  288.         }
  289.     }
  290.  
  291.     return CONNECT_E_NOCONNECTION;
  292. }
  293.  
  294. /////////////////////////////////////////////////////////////////////////////
  295. // CEnumConnections
  296.  
  297. class CEnumConnections : public CEnumArray
  298. {
  299. public:
  300.     CEnumConnections(const void* pvEnum, UINT nSize);
  301.     ~CEnumConnections();
  302.     void AddConnection(CONNECTDATA* pConn);
  303.  
  304. protected:
  305.     virtual BOOL OnNext(void* pv);
  306.     virtual CEnumArray* OnClone();
  307.  
  308.     UINT m_nMaxSize;    // number of items allocated (>= m_nSize)
  309.  
  310.     DECLARE_INTERFACE_MAP()
  311. };
  312.  
  313. BEGIN_INTERFACE_MAP(CEnumConnections, CEnumArray)
  314.     INTERFACE_PART(CEnumConnections, IID_IEnumConnections, EnumVOID)
  315. END_INTERFACE_MAP()
  316.  
  317.  
  318. CEnumConnections::CEnumConnections(const void* pvEnum, UINT nSize) :
  319.     CEnumArray(sizeof(CONNECTDATA), pvEnum, nSize, TRUE)
  320. {
  321.     m_nMaxSize = 0;
  322. }
  323.  
  324. CEnumConnections::~CEnumConnections()
  325. {
  326.     if (m_pClonedFrom == NULL)
  327.     {
  328.         UINT iCP;
  329.         CONNECTDATA* ppCP = (CONNECTDATA*)(VOID *)m_pvEnum;
  330.         for (iCP = 0; iCP < m_nSize; iCP++)
  331.             RELEASE(ppCP[iCP].pUnk);
  332.     }
  333.     // destructor will free the actual array (if it was not a clone)
  334. }
  335.  
  336. BOOL CEnumConnections::OnNext(void* pv)
  337. {
  338.     if (!CEnumArray::OnNext(pv))
  339.         return FALSE;
  340.  
  341.     // outgoing connection point needs to be AddRef'ed
  342.     //  (the caller has responsibility to release it)
  343.  
  344.     ((CONNECTDATA*)pv)->pUnk->AddRef();
  345.     return TRUE;
  346. }
  347.  
  348. CEnumArray* CEnumConnections::OnClone()
  349. {
  350.     ASSERT_VALID(this);
  351.     CEnumConnections* pClone;
  352.     pClone = new CEnumConnections(m_pvEnum, m_nSize);
  353.     pClone->m_bNeedFree = FALSE;
  354.     ASSERT(pClone != NULL);
  355.     ASSERT(!pClone->m_bNeedFree);   // clones should never free themselves
  356.     pClone->m_nCurPos = m_nCurPos;
  357.  
  358.     // finally, return the clone to OLE
  359.     ASSERT_VALID(pClone);
  360.     return pClone;
  361. }
  362.  
  363. void CEnumConnections::AddConnection(CONNECTDATA* pConn)
  364. {
  365.     ASSERT(m_nSize <= m_nMaxSize);
  366.  
  367.     if (m_nSize == m_nMaxSize)
  368.     {
  369.         // not enough space for new item -- allocate more
  370.         CONNECTDATA* pListNew = new CONNECTDATA[m_nSize+2];
  371.         m_nMaxSize += 2;
  372.         if (m_nSize > 0)
  373.             memcpy(pListNew, m_pvEnum, m_nSize*sizeof(CONNECTDATA));
  374.         delete m_pvEnum;
  375. #ifdef _WIN32
  376.         m_pvEnum = (BYTE*)pListNew;
  377. #else
  378.         m_pvEnum = (char*)pListNew;
  379. #endif
  380.     }
  381.  
  382.     // add this item to the list
  383.     ASSERT(m_nSize < m_nMaxSize);
  384.     ((CONNECTDATA*)m_pvEnum)[m_nSize] = *pConn;
  385.     pConn->pUnk->AddRef();
  386.     ++m_nSize;
  387. }
  388.  
  389. STDMETHODIMP CConnectionPoint::XConnPt::EnumConnections(LPENUMCONNECTIONS* ppEnum)
  390. {
  391.     METHOD_PROLOGUE_EX(CConnectionPoint, ConnPt)
  392.     CEnumConnections* pEnum = NULL;
  393.     CONNECTDATA cd;
  394.  
  395.     TRY
  396.     {
  397.         pEnum = new CEnumConnections(NULL, 0);
  398.  
  399.         if (pThis->m_pUnkFirstConnection != NULL)
  400.         {
  401.             cd.pUnk = pThis->m_pUnkFirstConnection;
  402.             cd.dwCookie = (DWORD)cd.pUnk;
  403.             pEnum->AddConnection(&cd);
  404.         }
  405.  
  406.         if (pThis->m_pConnections != NULL)
  407.         {
  408.             int cConnections = pThis->m_pConnections->GetSize();
  409.             for (int i = 0; i < cConnections; i++)
  410.             {
  411.                 cd.pUnk = (LPUNKNOWN)(pThis->m_pConnections->GetAt(i));
  412.                 cd.dwCookie = (DWORD)cd.pUnk;
  413.                 pEnum->AddConnection(&cd);
  414.             }
  415.         }
  416.     }
  417.     CATCH (CException, e)
  418.     {
  419.         delete pEnum;
  420.         pEnum = NULL;
  421.     }
  422.     END_CATCH
  423.  
  424.     if (pEnum != NULL)
  425.     {
  426.         // create and return the IEnumConnectionPoints object
  427.         *ppEnum = (IEnumConnections*)&pEnum->m_xEnumVOID;
  428.     }
  429.     else
  430.     {
  431.         // no connections: return NULL
  432.         *ppEnum = NULL;
  433.     }
  434.     return (pEnum != NULL) ? S_OK : E_OUTOFMEMORY;
  435. }
  436.  
  437.  
  438. /////////////////////////////////////////////////////////////////////////////
  439. // CEnumConnPoints
  440.  
  441. class CEnumConnPoints : public CEnumArray
  442. {
  443. public:
  444.     CEnumConnPoints(const void* pvEnum, UINT nSize);
  445.     ~CEnumConnPoints();
  446.     void AddConnPoint(LPCONNECTIONPOINT pConnPt);
  447.  
  448. protected:
  449.     virtual BOOL OnNext(void* pv);
  450.  
  451.     UINT m_nMaxSize;    // number of items allocated (>= m_nSize)
  452.  
  453.     DECLARE_INTERFACE_MAP()
  454. };
  455.  
  456. BEGIN_INTERFACE_MAP(CEnumConnPoints, CEnumArray)
  457.     INTERFACE_PART(CEnumConnPoints, IID_IEnumConnectionPoints, EnumVOID)
  458. END_INTERFACE_MAP()
  459.  
  460.  
  461. CEnumConnPoints::CEnumConnPoints(const void* pvEnum, UINT nSize) :
  462.     CEnumArray(sizeof(LPCONNECTIONPOINT), pvEnum, nSize, TRUE)
  463. {
  464.     m_nMaxSize = 0;
  465. }
  466.  
  467. CEnumConnPoints::~CEnumConnPoints()
  468. {
  469.     if (m_pClonedFrom == NULL)
  470.     {
  471.         UINT iCP;
  472.         LPCONNECTIONPOINT* ppCP =
  473.             (LPCONNECTIONPOINT*)(VOID *)m_pvEnum;
  474.         for (iCP = 0; iCP < m_nSize; iCP++)
  475.             RELEASE(ppCP[iCP]);
  476.     }
  477.     // destructor will free the actual array (if it was not a clone)
  478. }
  479.  
  480. BOOL CEnumConnPoints::OnNext(void* pv)
  481. {
  482.     if (!CEnumArray::OnNext(pv))
  483.         return FALSE;
  484.  
  485.     // outgoing connection point needs to be AddRef'ed
  486.     //  (the caller has responsibility to release it)
  487.  
  488.     (*(LPCONNECTIONPOINT*)pv)->AddRef();
  489.     return TRUE;
  490. }
  491.  
  492. void CEnumConnPoints::AddConnPoint(LPCONNECTIONPOINT pConnPt)
  493. {
  494.     ASSERT(m_nSize <= m_nMaxSize);
  495.  
  496.     if (m_nSize == m_nMaxSize)
  497.     {
  498.         // not enough space for new item -- allocate more
  499.         LPCONNECTIONPOINT* pListNew = new LPCONNECTIONPOINT[m_nSize+2];
  500.         m_nMaxSize += 2;
  501.         if (m_nSize > 0)
  502.             memcpy(pListNew, m_pvEnum, m_nSize*sizeof(LPCONNECTIONPOINT));
  503.         delete m_pvEnum;
  504. #ifdef _WIN32
  505.         m_pvEnum = (BYTE*)pListNew;
  506. #else
  507.         m_pvEnum = (char*)pListNew;
  508. #endif
  509.     }
  510.  
  511.     // add this item to the list
  512.     ASSERT(m_nSize < m_nMaxSize);
  513.     ((LPCONNECTIONPOINT*)m_pvEnum)[m_nSize] = pConnPt;
  514.     pConnPt->AddRef();
  515.     ++m_nSize;
  516. }
  517.  
  518.  
  519. /////////////////////////////////////////////////////////////////////////////
  520. // COleConnPtContainer
  521.  
  522. class COleConnPtContainer : public IConnectionPointContainer
  523. {
  524. public:
  525. #ifndef _AFX_NO_NESTED_DERIVATION
  526.     // required for METHOD_PROLOGUE_EX
  527.     size_t m_nOffset;
  528.     COleConnPtContainer::COleConnPtContainer()
  529.         { m_nOffset = offsetof(CCmdTarget, m_xConnPtContainer); }
  530. #endif
  531.  
  532.     STDMETHOD_(ULONG, AddRef)();
  533.     STDMETHOD_(ULONG, Release)();
  534.     STDMETHOD(QueryInterface)(REFIID, LPVOID*);
  535.  
  536.     STDMETHOD(EnumConnectionPoints)(LPENUMCONNECTIONPOINTS* ppEnum);
  537.     STDMETHOD(FindConnectionPoint)(REFIID iid, LPCONNECTIONPOINT* ppCP);
  538. };
  539.  
  540. STDMETHODIMP_(ULONG) COleConnPtContainer::AddRef()
  541. {
  542.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  543.     return (ULONG)pThis->ExternalAddRef();
  544. }
  545.  
  546. STDMETHODIMP_(ULONG) COleConnPtContainer::Release()
  547. {
  548.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  549.     return (ULONG)pThis->ExternalRelease();
  550. }
  551.  
  552. STDMETHODIMP COleConnPtContainer::QueryInterface(
  553.     REFIID iid, LPVOID* ppvObj)
  554. {
  555.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  556.     return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
  557. }
  558.  
  559. STDMETHODIMP COleConnPtContainer::EnumConnectionPoints(
  560.     LPENUMCONNECTIONPOINTS* ppEnum)
  561. {
  562.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  563.  
  564.     CEnumConnPoints* pEnum = NULL;
  565.  
  566.     TRY
  567.     {
  568.         pEnum = new CEnumConnPoints(NULL, 0);
  569.  
  570.         // Add connection points that aren't in the connection map
  571.         CPtrArray ptrArray;
  572.         if (pThis->GetExtraConnectionPoints(&ptrArray))
  573.         {
  574.             for (int i = 0; i < ptrArray.GetSize(); i++)
  575.                 pEnum->AddConnPoint((LPCONNECTIONPOINT)ptrArray.GetAt(i));
  576.         }
  577.  
  578.         // walk the chain of connection maps
  579.         const AFX_CONNECTIONMAP* pMap = pThis->GetConnectionMap();
  580.         const AFX_CONNECTIONMAP_ENTRY* pEntry;
  581.  
  582.         while (pMap != NULL)
  583.         {
  584.             pEntry = pMap->pEntry;
  585.  
  586.             while (pEntry->piid != NULL)
  587.             {
  588.                 pEnum->AddConnPoint(GetConnectionPtr(pThis, pEntry));
  589.                 ++pEntry;
  590.             }
  591. #ifdef _AFXDLL
  592.             pMap = (*pMap->pfnGetBaseMap)();
  593. #else
  594.             pMap = pMap->pBaseMap;
  595. #endif
  596.         }
  597.     }
  598.     CATCH (CException, e)
  599.     {
  600.         delete pEnum;
  601.         pEnum = NULL;
  602.     }
  603.     END_CATCH
  604.  
  605.     if (pEnum != NULL)
  606.     {
  607.         // create and return the IEnumConnectionPoints object
  608.         *ppEnum = (IEnumConnectionPoints*)&pEnum->m_xEnumVOID;
  609.     }
  610.     else
  611.     {
  612.         // no connection points: return NULL
  613.         *ppEnum = NULL;
  614.     }
  615.  
  616.     return (pEnum != NULL) ? S_OK : CONNECT_E_NOCONNECTION;
  617. }
  618.  
  619. STDMETHODIMP COleConnPtContainer::FindConnectionPoint(
  620.     REFIID iid, LPCONNECTIONPOINT* ppCP)
  621. {
  622.     METHOD_PROLOGUE_EX_(CCmdTarget, ConnPtContainer)
  623.     ASSERT(ppCP != NULL);
  624.  
  625.     if ((*ppCP = pThis->GetConnectionHook(iid)) != NULL)
  626.     {
  627.         (*ppCP)->AddRef();
  628.         return S_OK;
  629.     }
  630.  
  631.     const AFX_CONNECTIONMAP* pMap = pThis->GetConnectionMap();
  632.     const AFX_CONNECTIONMAP_ENTRY* pEntry;
  633.  
  634.     while (pMap != NULL)
  635.     {
  636.         pEntry = pMap->pEntry;
  637.  
  638.         while (pEntry->piid != NULL)
  639.         {
  640.             if (IsEqualIID(iid, *(IID*)(pEntry->piid)))
  641.             {
  642.                 *ppCP = GetConnectionPtr(pThis, pEntry);
  643.                 (*ppCP)->AddRef();
  644.                 return S_OK;
  645.             }
  646.             ++pEntry;
  647.         }
  648. #ifdef _AFXDLL
  649.         pMap = (*pMap->pfnGetBaseMap)();
  650. #else
  651.         pMap = pMap->pBaseMap;
  652. #endif
  653.     }
  654.  
  655.     return E_NOINTERFACE;
  656. }
  657.  
  658.  
  659. /////////////////////////////////////////////////////////////////////////////
  660. // Wiring CCmdTarget to COleConnPtContainer
  661.  
  662. // enable this object for OLE connections, called from derived class ctor
  663. void CCmdTarget::EnableConnections()
  664. {
  665.     ASSERT(GetConnectionMap() != NULL);   // must have DECLARE_DISPATCH_MAP
  666.  
  667.     // construct an COleConnPtContainer instance just to get to the vtable
  668.     COleConnPtContainer cpc;
  669.  
  670.     // vtable pointer should be already set to same or NULL
  671.     ASSERT(m_xConnPtContainer.m_vtbl == NULL||
  672.         *(DWORD*)&cpc == m_xConnPtContainer.m_vtbl);
  673.     // verify that sizes match
  674.     ASSERT(sizeof(m_xConnPtContainer) == sizeof(COleConnPtContainer));
  675.  
  676.     // copy the vtable (and other data) to make sure it is initialized
  677.     m_xConnPtContainer.m_vtbl = *(DWORD*)&cpc;
  678.     *(COleConnPtContainer*)&m_xConnPtContainer = cpc;
  679. }
  680.  
  681. /////////////////////////////////////////////////////////////////////////////
  682. // Force any extra compiler-generated code into AFX_INIT_SEG
  683.  
  684. #ifdef AFX_INIT_SEG
  685. #pragma code_seg(AFX_INIT_SEG)
  686. #endif
  687.