home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLEUNK.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  12.8 KB  |  470 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 AFX_OLE_SEG
  14. #pragma code_seg(AFX_OLE_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. // Debug helpers
  26.  
  27. #ifdef _DEBUG
  28. // Helper for converting IID into useful string.  Only for debugging.
  29. LPCTSTR AFXAPI AfxGetIIDString(REFIID iid)
  30. {
  31.     static TCHAR szUnfamiliar[80];
  32.     TCHAR szByte[3];
  33.  
  34.     struct IID_ENTRY
  35.     {
  36.         const IID* piid;
  37.         LPCTSTR lpszName;
  38.     };
  39.  
  40. #define MAKE_IID_ENTRY(name) { &name, _T(#name) }
  41.  
  42.     static const IID_ENTRY iidNameTable[] =
  43.     {
  44.         MAKE_IID_ENTRY(IID_IAdviseSink),
  45.         MAKE_IID_ENTRY(IID_IAdviseSink2),
  46.         MAKE_IID_ENTRY(IID_IBindCtx),
  47.         MAKE_IID_ENTRY(IID_IClassFactory),
  48. #ifndef _MAC
  49.         MAKE_IID_ENTRY(IID_IContinueCallback),
  50.         MAKE_IID_ENTRY(IID_IEnumOleDocumentViews),
  51.         MAKE_IID_ENTRY(IID_IOleCommandTarget),
  52.         MAKE_IID_ENTRY(IID_IOleDocument),
  53.         MAKE_IID_ENTRY(IID_IOleDocumentSite),
  54.         MAKE_IID_ENTRY(IID_IOleDocumentView),
  55.         MAKE_IID_ENTRY(IID_IPrint),
  56. #endif
  57.         MAKE_IID_ENTRY(IID_IDataAdviseHolder),
  58.         MAKE_IID_ENTRY(IID_IDataObject),
  59.         MAKE_IID_ENTRY(IID_IDebug),
  60.         MAKE_IID_ENTRY(IID_IDebugStream),
  61.         MAKE_IID_ENTRY(IID_IDfReserved1),
  62.         MAKE_IID_ENTRY(IID_IDfReserved2),
  63.         MAKE_IID_ENTRY(IID_IDfReserved3),
  64.         MAKE_IID_ENTRY(IID_IDispatch),
  65.         MAKE_IID_ENTRY(IID_IDropSource),
  66.         MAKE_IID_ENTRY(IID_IDropTarget),
  67.         MAKE_IID_ENTRY(IID_IEnumCallback),
  68.         MAKE_IID_ENTRY(IID_IEnumFORMATETC),
  69.         MAKE_IID_ENTRY(IID_IEnumGeneric),
  70.         MAKE_IID_ENTRY(IID_IEnumHolder),
  71.         MAKE_IID_ENTRY(IID_IEnumMoniker),
  72.         MAKE_IID_ENTRY(IID_IEnumOLEVERB),
  73.         MAKE_IID_ENTRY(IID_IEnumSTATDATA),
  74.         MAKE_IID_ENTRY(IID_IEnumSTATSTG),
  75.         MAKE_IID_ENTRY(IID_IEnumString),
  76.         MAKE_IID_ENTRY(IID_IEnumUnknown),
  77.         MAKE_IID_ENTRY(IID_IEnumVARIANT),
  78. //      MAKE_IID_ENTRY(IID_IExternalConnection),
  79.         MAKE_IID_ENTRY(IID_IInternalMoniker),
  80.         MAKE_IID_ENTRY(IID_ILockBytes),
  81.         MAKE_IID_ENTRY(IID_IMalloc),
  82.         MAKE_IID_ENTRY(IID_IMarshal),
  83.         MAKE_IID_ENTRY(IID_IMessageFilter),
  84.         MAKE_IID_ENTRY(IID_IMoniker),
  85.         MAKE_IID_ENTRY(IID_IOleAdviseHolder),
  86.         MAKE_IID_ENTRY(IID_IOleCache),
  87.         MAKE_IID_ENTRY(IID_IOleCache2),
  88.         MAKE_IID_ENTRY(IID_IOleCacheControl),
  89.         MAKE_IID_ENTRY(IID_IOleClientSite),
  90.         MAKE_IID_ENTRY(IID_IOleContainer),
  91.         MAKE_IID_ENTRY(IID_IOleInPlaceActiveObject),
  92.         MAKE_IID_ENTRY(IID_IOleInPlaceFrame),
  93.         MAKE_IID_ENTRY(IID_IOleInPlaceObject),
  94.         MAKE_IID_ENTRY(IID_IOleInPlaceSite),
  95.         MAKE_IID_ENTRY(IID_IOleInPlaceUIWindow),
  96.         MAKE_IID_ENTRY(IID_IOleItemContainer),
  97.         MAKE_IID_ENTRY(IID_IOleLink),
  98.         MAKE_IID_ENTRY(IID_IOleManager),
  99.         MAKE_IID_ENTRY(IID_IOleObject),
  100.         MAKE_IID_ENTRY(IID_IOlePresObj),
  101.         MAKE_IID_ENTRY(IID_IOleWindow),
  102.         MAKE_IID_ENTRY(IID_IPSFactory),
  103.         MAKE_IID_ENTRY(IID_IParseDisplayName),
  104.         MAKE_IID_ENTRY(IID_IPersist),
  105.         MAKE_IID_ENTRY(IID_IPersistFile),
  106.         MAKE_IID_ENTRY(IID_IPersistStorage),
  107.         MAKE_IID_ENTRY(IID_IPersistStream),
  108.         MAKE_IID_ENTRY(IID_IProxyManager),
  109.         MAKE_IID_ENTRY(IID_IRootStorage),
  110.         MAKE_IID_ENTRY(IID_IRpcChannel),
  111.         MAKE_IID_ENTRY(IID_IRpcProxy),
  112.         MAKE_IID_ENTRY(IID_IRpcStub),
  113.         MAKE_IID_ENTRY(IID_IRunnableObject),
  114.         MAKE_IID_ENTRY(IID_IRunningObjectTable),
  115.         MAKE_IID_ENTRY(IID_IStdMarshalInfo),
  116.         MAKE_IID_ENTRY(IID_IStorage),
  117.         MAKE_IID_ENTRY(IID_IStream),
  118.         MAKE_IID_ENTRY(IID_IStubManager),
  119.         MAKE_IID_ENTRY(IID_IUnknown),
  120.         MAKE_IID_ENTRY(IID_IViewObject),
  121.         MAKE_IID_ENTRY(IID_IViewObject2),
  122.         MAKE_IID_ENTRY(IID_NULL),
  123.     };
  124. #undef MAKE_IID_ENTRY
  125.  
  126.     // look for it in the table
  127.     for (int i = 0; i < _countof(iidNameTable); i++)
  128.     {
  129.         if (iid == *iidNameTable[i].piid)
  130.             return iidNameTable[i].lpszName;
  131.     }
  132.     // if we get here, it is some IID_ we haven't heard of...
  133.  
  134.     wsprintf(szUnfamiliar, _T("%8.8X-%4.4X-%4.4X-"),
  135.         iid.Data1, iid.Data2, iid.Data3);
  136.     for (int nIndex = 0; nIndex < 8; nIndex++)
  137.     {
  138.         wsprintf(szByte, _T("%2.2X"), iid.Data4[nIndex]);
  139.         _tcscat(szUnfamiliar, szByte);
  140.     }
  141.  
  142.     return szUnfamiliar;
  143. }
  144. #endif
  145.  
  146. /////////////////////////////////////////////////////////////////////////////
  147. // Component object model helpers
  148.  
  149. /////////////////////////////////////////////////////////////////////////////
  150. // IUnknown client helpers
  151.  
  152. LPUNKNOWN AFXAPI _AfxQueryInterface(LPUNKNOWN lpUnknown, REFIID iid)
  153. {
  154.     ASSERT(lpUnknown != NULL);
  155.  
  156.     LPUNKNOWN lpW = NULL;
  157.     if (lpUnknown->QueryInterface(iid, (LPLP)&lpW) != S_OK)
  158.         return NULL;
  159.  
  160.     return lpW;
  161. }
  162.  
  163. DWORD AFXAPI _AfxRelease(LPUNKNOWN* lplpUnknown)
  164. {
  165.     ASSERT(lplpUnknown != NULL);
  166.     if (*lplpUnknown != NULL)
  167.     {
  168.         DWORD dwRef = (*lplpUnknown)->Release();
  169.         *lplpUnknown = NULL;
  170.         return dwRef;
  171.     }
  172.     return 0;
  173. }
  174.  
  175. #define GetInterfacePtr(pTarget, pEntry) \
  176.     ((LPUNKNOWN)((BYTE*)pTarget + pEntry->nOffset))
  177.  
  178. #define GetAggregatePtr(pTarget, pEntry) \
  179.     (*(LPUNKNOWN*)((BYTE*)pTarget + pEntry->nOffset))
  180.  
  181. /////////////////////////////////////////////////////////////////////////////
  182. // CCmdTarget interface map implementation
  183.  
  184. // support for aggregation
  185. class CInnerUnknown : public IUnknown
  186. {
  187. public:
  188.     STDMETHOD_(ULONG, AddRef)();
  189.     STDMETHOD_(ULONG, Release)();
  190.     STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj);
  191. };
  192.  
  193. // calling this function enables an object to be aggregatable
  194. void CCmdTarget::EnableAggregation()
  195. {
  196.     // construct an CInnerUnknown just to get to the vtable
  197.     CInnerUnknown innerUnknown;
  198.  
  199.     // copy the vtable & make sure initialized
  200.     ASSERT(sizeof(m_xInnerUnknown) == sizeof(CInnerUnknown));
  201.     m_xInnerUnknown = *(DWORD*)&innerUnknown;
  202. }
  203.  
  204. DWORD CCmdTarget::ExternalAddRef()
  205. {
  206.     // delegate to controlling unknown if aggregated
  207.     if (m_pOuterUnknown != NULL)
  208.         return m_pOuterUnknown->AddRef();
  209.  
  210.     return InternalAddRef();
  211. }
  212.  
  213. DWORD CCmdTarget::InternalRelease()
  214. {
  215.     ASSERT(GetInterfaceMap() != NULL);
  216.  
  217.     if (m_dwRef == 0)
  218.         return 0;
  219.  
  220.     LONG lResult = InterlockedDecrement(&m_dwRef);
  221.     if (lResult == 0)
  222.     {
  223.         AFX_MANAGE_STATE(m_pModuleState);
  224.         OnFinalRelease();
  225.     }
  226.     return lResult;
  227. }
  228.  
  229. DWORD CCmdTarget::ExternalRelease()
  230. {
  231.     // delegate to controlling unknown if aggregated
  232.     if (m_pOuterUnknown != NULL)
  233.         return m_pOuterUnknown->Release();
  234.  
  235.     return InternalRelease();
  236. }
  237.  
  238. // special QueryInterface used in implementation (does not AddRef)
  239. LPUNKNOWN CCmdTarget::GetInterface(const void* iid)
  240. {
  241.     // allow general hook first chance
  242.     LPUNKNOWN lpUnk;
  243.     if ((lpUnk = GetInterfaceHook(iid)) != NULL)
  244.         return lpUnk;
  245.  
  246.     const AFX_INTERFACEMAP* pMap = GetInterfaceMap();
  247.     ASSERT(pMap != NULL);
  248.     DWORD lData1 = ((IID*)iid)->Data1;
  249.  
  250.     // IUnknown is a special case since nobody really implements *only* it!
  251.     BOOL bUnknown = ((DWORD*)&IID_IUnknown)[0] == lData1 &&
  252.         ((DWORD*)iid)[1] == ((DWORD*)&IID_IUnknown)[1] &&
  253.         ((DWORD*)iid)[2] == ((DWORD*)&IID_IUnknown)[2] &&
  254.         ((DWORD*)iid)[3] == ((DWORD*)&IID_IUnknown)[3];
  255.     if (bUnknown)
  256.     {
  257.         do
  258.         {
  259.             const AFX_INTERFACEMAP_ENTRY* pEntry = pMap->pEntry;
  260.             ASSERT(pEntry != NULL);
  261.             while (pEntry->piid != NULL)
  262.             {
  263.                 // check INTERFACE_ENTRY macro
  264.                 LPUNKNOWN lpUnk = GetInterfacePtr(this, pEntry);
  265.  
  266.                 // check vtable pointer (can be NULL)
  267.                 if (*(DWORD*)lpUnk != 0)
  268.                     return lpUnk;
  269.  
  270.                 // entry did not match -- keep looking
  271.                 ++pEntry;
  272.             }
  273. #ifdef _AFXDLL
  274.         } while ((pMap = (*pMap->pfnGetBaseMap)()) != NULL);
  275. #else
  276.         } while ((pMap = pMap->pBaseMap) != NULL);
  277. #endif
  278.  
  279.         // interface ID not found, fail the call
  280.         return NULL;
  281.     }
  282.  
  283.     // otherwise, walk the interface map to find the matching IID
  284.     do
  285.     {
  286.         const AFX_INTERFACEMAP_ENTRY* pEntry = pMap->pEntry;
  287.         ASSERT(pEntry != NULL);
  288.         while (pEntry->piid != NULL)
  289.         {
  290.             if (((DWORD*)pEntry->piid)[0] == lData1 &&
  291.                 ((DWORD*)pEntry->piid)[1] == ((DWORD*)iid)[1] &&
  292.                 ((DWORD*)pEntry->piid)[2] == ((DWORD*)iid)[2] &&
  293.                 ((DWORD*)pEntry->piid)[3] == ((DWORD*)iid)[3])
  294.             {
  295.                 // check INTERFACE_ENTRY macro
  296.                 LPUNKNOWN lpUnk = GetInterfacePtr(this, pEntry);
  297.  
  298.                 // check vtable pointer (can be NULL)
  299.                 if (*(DWORD*)lpUnk != 0)
  300.                     return lpUnk;
  301.             }
  302.  
  303.             // entry did not match -- keep looking
  304.             ++pEntry;
  305.         }
  306. #ifdef _AFXDLL
  307.     } while ((pMap = (*pMap->pfnGetBaseMap)()) != NULL);
  308. #else
  309.     } while ((pMap = pMap->pBaseMap) != NULL);
  310. #endif
  311.  
  312.     // interface ID not found, fail the call
  313.     return NULL;
  314. }
  315.  
  316. LPUNKNOWN CCmdTarget::QueryAggregates(const void* iid)
  317. {
  318.     const AFX_INTERFACEMAP* pMap = GetInterfaceMap();
  319.     ASSERT(pMap != NULL);
  320.  
  321.     // walk the Interface map to call aggregates
  322.     do
  323.     {
  324.         const AFX_INTERFACEMAP_ENTRY* pEntry = pMap->pEntry;
  325.         // skip non-aggregate entries
  326.         ASSERT(pEntry != NULL);
  327.         while (pEntry->piid != NULL)
  328.             ++pEntry;
  329.  
  330.         // call QueryInterface for each aggregate entry
  331.         while (pEntry->nOffset != (size_t)-1)
  332.         {
  333.             LPUNKNOWN lpQuery = GetAggregatePtr(this, pEntry);
  334.             // it is ok to have aggregate but not created yet
  335.             if (lpQuery != NULL)
  336.             {
  337.                 LPUNKNOWN lpUnk = NULL;
  338.                 if (lpQuery->QueryInterface(*(IID*)iid, (LPLP)&lpUnk)
  339.                     == S_OK && lpUnk != NULL)
  340.                 {
  341.                     // QueryInterface successful...
  342.                     return lpUnk;
  343.                 }
  344.             }
  345.  
  346.             // entry did not match -- keep looking
  347.             ++pEntry;
  348.         }
  349. #ifdef _AFXDLL
  350.     } while ((pMap = (*pMap->pfnGetBaseMap)()) != NULL);
  351. #else
  352.     } while ((pMap = pMap->pBaseMap) != NULL);
  353. #endif
  354.  
  355.     // interface ID not found, fail the call
  356.     return NULL;
  357. }
  358.  
  359. // real implementation of QueryInterface
  360. DWORD CCmdTarget::InternalQueryInterface(const void* iid, LPVOID* ppvObj)
  361. {
  362.     IID* piid = (IID*) iid;
  363.  
  364.     // check local interfaces
  365.     if ((*ppvObj = GetInterface(iid)) != NULL)
  366.     {
  367.         // interface was found -- add a reference
  368.         ExternalAddRef();
  369.         return S_OK;
  370.     }
  371.  
  372.     // check aggregates
  373.     if ((*ppvObj = QueryAggregates(iid)) != NULL)
  374.         return S_OK;
  375.  
  376.     // interface ID not found, fail the call
  377.     return (DWORD)E_NOINTERFACE;
  378. }
  379.  
  380. // QueryInterface that is exported to normal clients
  381. DWORD CCmdTarget::ExternalQueryInterface(const void* iid,
  382.     LPVOID* ppvObj)
  383. {
  384.     // delegate to controlling unknown if aggregated
  385.     if (m_pOuterUnknown != NULL)
  386.         return m_pOuterUnknown->QueryInterface(*(IID*)iid, ppvObj);
  387.  
  388.     return InternalQueryInterface(iid, ppvObj);
  389. }
  390.  
  391. /////////////////////////////////////////////////////////////////////////////
  392. // Inner IUnknown implementation (for aggregation)
  393.  
  394. STDMETHODIMP_(ULONG) CInnerUnknown::AddRef()
  395. {
  396.     METHOD_PROLOGUE_(CCmdTarget, InnerUnknown)
  397.     return pThis->InternalAddRef();
  398. }
  399.  
  400. STDMETHODIMP_(ULONG) CInnerUnknown::Release()
  401. {
  402.     METHOD_PROLOGUE(CCmdTarget, InnerUnknown)
  403.     return pThis->InternalRelease();
  404. }
  405.  
  406. STDMETHODIMP CInnerUnknown::QueryInterface(REFIID iid, LPVOID* ppvObj)
  407. {
  408.     METHOD_PROLOGUE_(CCmdTarget, InnerUnknown)
  409.  
  410.     if (iid == IID_IUnknown)
  411.     {
  412.         // QueryInterface on inner IUnknown for IID_IUnknown must
  413.         //  return inner IUnknown.
  414.         pThis->InternalAddRef();
  415.         *ppvObj = this;
  416.         return S_OK;
  417.     }
  418.     return pThis->InternalQueryInterface(&iid, ppvObj);
  419. }
  420.  
  421. /////////////////////////////////////////////////////////////////////////////
  422. // other helper functions
  423.  
  424. // ExternalDisconnect is used to remove RPC connections in destructors.  This
  425. //  insures that no RPC calls will go to the object after it has been
  426. //  deleted.
  427. void CCmdTarget::ExternalDisconnect()
  428. {
  429.     if (m_dwRef == 0)   // already in disconnected state?
  430.         return;
  431.  
  432.     // get IUnknown pointer for the object
  433.     LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
  434.     ASSERT(lpUnknown != NULL);
  435.  
  436.     // disconnect the object
  437.     InterlockedIncrement(&m_dwRef);  // protect object from destruction
  438.     CoDisconnectObject(lpUnknown, 0);
  439.     m_dwRef = 0;    // now in disconnected state
  440. }
  441.  
  442. // GetControllingUnknown is used when creating aggregate objects,
  443. //  usually from OnCreateAggregates.  The outer, or controlling, unknown
  444. //  is one of the parameters to CoCreateInstance and other OLE creation
  445. //  functions which support aggregation.
  446. LPUNKNOWN CCmdTarget::GetControllingUnknown()
  447. {
  448.     if (m_pOuterUnknown != NULL)
  449.         return m_pOuterUnknown; // aggregate of m_pOuterUnknown
  450.  
  451.     LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
  452.     return lpUnknown;   // return our own IUnknown implementation
  453. }
  454.  
  455. /////////////////////////////////////////////////////////////////////////////
  456. // Inline function declarations expanded out-of-line
  457.  
  458. #ifndef _AFX_ENABLE_INLINES
  459.  
  460. // expand inlines for OLE general APIs
  461. static char _szAfxOleInl[] = "afxole.inl";
  462. #undef THIS_FILE
  463. #define THIS_FILE _szAfxOleInl
  464. #define _AFXDISP_INLINE
  465. #include "afxole.inl"
  466.  
  467. #endif //!_AFX_ENABLE_INLINES
  468.  
  469. /////////////////////////////////////////////////////////////////////////////
  470.