oleunk.cpp 13 KB

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