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