Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

379 lines
10 KiB

  1. /*
  2. * e x o . c p p
  3. *
  4. * Purpose:
  5. * Base Exchange COM Object
  6. *
  7. * Any Exchange object that implements one or more COM interfaces
  8. * should 'derive' from EXObject using the macros below.
  9. *
  10. * Originator:
  11. * JohnKal
  12. * Owner:
  13. * BeckyAn
  14. *
  15. * Copyright (C) Microsoft Corp 1993-1997. All rights reserved.
  16. */
  17. #pragma warning(disable:4201) /* nameless struct/union */
  18. #pragma warning(disable:4514) /* unreferenced inline function */
  19. #include <windows.h>
  20. #include <windowsx.h>
  21. #include <ole2.h>
  22. #include <caldbg.h>
  23. #include "exo.h"
  24. #ifndef NCHAR
  25. #define NCHAR CHAR
  26. #endif // !NCHAR
  27. // Debugging traces.
  28. // Change the function name in the define to match your system's debug calls.
  29. #ifdef DBG
  30. BOOL g_fExoDebugTraceOn = -1;
  31. #define ExoDebugTrace (!g_fExoDebugTraceOn)?0:DebugTrace
  32. #else // !DBG
  33. #define ExoDebugTrace 1?0:DebugTrace
  34. #endif // DBG, else
  35. // Forward function declarations ////////////////////////////////////////
  36. #ifdef DBG
  37. // EXO supporting debug structures.
  38. #define IID_PAIR(_iid) { (IID *) & IID_ ## _iid, #_iid }
  39. const struct
  40. {
  41. IID * piid;
  42. LPSTR szIidName;
  43. } c_rgiidpair[] =
  44. {
  45. IID_PAIR(IUnknown),
  46. IID_PAIR(IDataObject),
  47. // IID_PAIR(IMAPITable),
  48. IID_PAIR(IOleObject),
  49. IID_PAIR(IOleInPlaceObject),
  50. IID_PAIR(IPersist),
  51. // IID_PAIR(IPersistMessage),
  52. IID_PAIR(IPersistStorage),
  53. IID_PAIR(IStorage),
  54. IID_PAIR(IStream),
  55. IID_PAIR(IViewObject),
  56. IID_PAIR(IViewObject2),
  57. // IID_PAIR(IMAPIForm),
  58. // IID_PAIR(IMAPIFormAdviseSink),
  59. // IID_PAIR(IMAPISession),
  60. IID_PAIR(IMoniker),
  61. IID_PAIR(IROTData),
  62. { 0, 0 } // end of table marker.
  63. };
  64. // EXO supporting debug function.
  65. // Gets a name for a given IID.
  66. LPCSTR NszFromIid(REFIID riid)
  67. {
  68. int i = 0;
  69. static NCHAR rgnch[80]; //$ REVIEW: not thread safe.
  70. while (c_rgiidpair[i].piid)
  71. {
  72. if (*c_rgiidpair[i].piid == riid)
  73. return c_rgiidpair[i].szIidName;
  74. ++i;
  75. }
  76. wsprintfA(rgnch, "{%08lx-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x}",
  77. riid.Data1, riid.Data2, riid.Data3,
  78. riid.Data4[0],riid.Data4[1],riid.Data4[2],riid.Data4[3],
  79. riid.Data4[4],riid.Data4[5],riid.Data4[6],riid.Data4[7]);
  80. return rgnch;
  81. }
  82. #endif // DBG
  83. // EXO base class: implementation ////////////////////////////////////////
  84. // EXO's own interface mapping table & class info definitions.
  85. BEGIN_INTERFACE_TABLE(EXO)
  86. END_INTERFACE_TABLE(EXO);
  87. DECLARE_EXOCLSINFO(EXO) =
  88. EXOCLSINFO_CONTENT_EX( EXO, NULL, exotypNonserver, &CLSID_NULL, NULL );
  89. EXO::EXO() :
  90. m_cRef(1)
  91. {
  92. }
  93. EXO::~EXO()
  94. { // must have this or linker whines.
  95. }
  96. /*
  97. * EXO::InternalQueryInterface
  98. *
  99. * Purpose:
  100. * Given an interface ID, check to see if the object implements the interface.
  101. * If the interface is supported, return a pointer to it.
  102. * Otherwise, return E_NOINTERFACE.
  103. * This function scans the object's classinfo chain, starting at the lowest
  104. * level, looking for the requested IID. The lowest classinfo struct is
  105. * obtained by calling a virtual function.
  106. *
  107. * Arguments:
  108. * riid in IID of the requested interface.
  109. * ppvOut out Returned interface pointer.
  110. *
  111. * Returns:
  112. * S_OK or E_NOINTERFACE.
  113. *
  114. * Notes:
  115. * This needs to be virtual for several reasons:
  116. * 1) so classes derived from EXO can aggregate other objects and still have EXO routines
  117. * access the interfaces of the aggregated object,
  118. * 2) so that EXOA_UNK members can call it
  119. * All QI work should be routed here using EXO[A]_INCLASS_DECL().
  120. * (The only exception is if you are an aggregator -- you have a kid --
  121. * and then you should still CALL this function to search throught your own interfaces.)
  122. * Notes:
  123. * Note that pexoclsinfo is looked up using the virtual call to GetEXOClassInfo instead of using the object's m_pexoclsinfo. This is so
  124. * that a derived object's IIDINFO table need only contain interfaces new to that object instead of
  125. * all the interfaces of the derived object and all the interfaces of it's parent.
  126. * A class's InternalQueryInterface() method general calls this method explicitly passing
  127. * the classes EXOCLSINFO (*not* m_pexoclsinfo) and if that fails calls it's parent's
  128. * InternalQueryInterface().
  129. */
  130. HRESULT EXO::InternalQueryInterface(REFIID riid, LPVOID * ppvOut)
  131. {
  132. UINT ciidinfo;
  133. const EXOCLSINFO * pexoclsinfo;
  134. const IIDINFO * piidinfo;
  135. #ifdef DBG
  136. #ifdef UNICODE
  137. UsesMakeANSI;
  138. LPCSTR szClassName = MakeANSI(GetEXOClassInfo()->szClassName);
  139. #else // !UNICODE
  140. LPCSTR szClassName = GetEXOClassInfo()->szClassName;
  141. #endif // !UNICODE
  142. ExoDebugTrace("%s::QueryInterface(%08lx): being asked for %s\n", szClassName, this, NszFromIid(riid));
  143. #endif // DBG
  144. Assert(ppvOut);
  145. *ppvOut = NULL;
  146. // Get the lowest (leaf) classinfo for this object.
  147. pexoclsinfo = GetEXOClassInfo();
  148. // Search up the classinfo chain. EXO's parent classinfo pointer is NULL,
  149. // and will terminate this loop.
  150. while (pexoclsinfo)
  151. {
  152. // Get the interface mapping table from the classinfo struct.
  153. ciidinfo = pexoclsinfo->ciidinfo;
  154. piidinfo = pexoclsinfo->rgiidinfo;
  155. // Search through this interface mapping table.
  156. for ( ; ciidinfo--; ++piidinfo)
  157. {
  158. // If the iid is found.
  159. if (*piidinfo->iid == riid)
  160. {
  161. // Apply the offset for this iid.
  162. IUnknown * const punk = EXOApplyDbCast(IUnknown, this,
  163. piidinfo->cbDown, piidinfo->cbUp);
  164. #ifdef DBG
  165. // Uses a debug-only variable.
  166. ExoDebugTrace("%s::QueryInterface(%08lx): cRef: %d -> %d\n", szClassName, this, m_cRef, m_cRef+1);
  167. #endif // DBG
  168. // Need to AddRef the resulting object. This ref is for the caller.
  169. *ppvOut = punk;
  170. punk->AddRef();
  171. return S_OK;
  172. }
  173. }
  174. // Fetch the next classinfo struct up the chain.
  175. pexoclsinfo = pexoclsinfo->pexoclsinfoParent;
  176. }
  177. // No support for the requested inteface.
  178. #ifdef DBG
  179. // Uses a debug-only variable.
  180. ExoDebugTrace("%s::QueryInterface(%08lx): E_NOINTERFACE\n", szClassName, this);
  181. #endif // DBG
  182. return E_NOINTERFACE;
  183. }
  184. /*
  185. * EXO::InternalAddRef
  186. *
  187. * Purpose:
  188. * Increments the reference count on the object.
  189. *
  190. * Arguments:
  191. * None.
  192. *
  193. * Returns:
  194. * The new reference count.
  195. */
  196. ULONG EXO::InternalAddRef()
  197. {
  198. #ifdef DBG
  199. #ifdef UNICODE
  200. UsesMakeANSI;
  201. ExoDebugTrace("%s::AddRef(%08lx): cRef: %ld->%ld\n", MakeANSI(GetEXOClassInfo()->szClassName), this, m_cRef, m_cRef+1);
  202. #else // !UNICODE
  203. ExoDebugTrace("%s::AddRef(%08lx): cRef: %ld->%ld\n", GetEXOClassInfo()->szClassName, this, m_cRef, m_cRef+1);
  204. #endif // !UNICODE
  205. #endif // DBG
  206. // NOTE: On Win95 or NT3.51, this won't return the exact m_cRef....
  207. // (People shouldn't depend on the value returned from AddRef anyway!!!)
  208. //
  209. return InterlockedIncrement(&m_cRef);
  210. }
  211. /*
  212. * EXO::InternalRelease
  213. *
  214. * Purpose:
  215. * Decrements the reference count on the object. If the reference
  216. * count reaches zero, we destroy the object.
  217. *
  218. * Arguments:
  219. * None.
  220. *
  221. * Returns:
  222. * The new reference count, 0 if the object is destroyed.
  223. */
  224. ULONG EXO::InternalRelease()
  225. {
  226. ULONG cRef;
  227. #ifdef DBG
  228. #ifdef UNICODE
  229. UsesMakeANSI;
  230. ExoDebugTrace("%s::Release(%08lx): cRef: %ld->%ld\n", MakeANSI(GetEXOClassInfo()->szClassName), this, m_cRef, m_cRef-1);
  231. #else // !UNICODE
  232. ExoDebugTrace("%s::Release(%08lx): cRef: %ld->%ld\n", GetEXOClassInfo()->szClassName, this, m_cRef, m_cRef-1);
  233. #endif // !UNICODE
  234. #endif // DBG
  235. AssertSz(m_cRef > 0, "cRef is already 0!");
  236. cRef = InterlockedDecrement(&m_cRef);
  237. if (0 == cRef)
  238. {
  239. delete this;
  240. return 0;
  241. }
  242. return cRef;
  243. }
  244. // Implementation of EXOA::EXOA_UNK methods //////////////////
  245. /*
  246. * EXOA::EXOA_UNK::QueryInterface
  247. *
  248. * Purpose:
  249. * Given an interface ID 'riid', first calls out through a virtual
  250. * function EXOA::AggregatorQueryInterface() to allow an aggregated
  251. * aggregator to QI any of his children for the interface pointer.
  252. * If that doesn't result in an interface, we then perform the
  253. * EXO::QueryInterface() scan on the derived object itself.
  254. *
  255. * Arguments:
  256. * riid in IID of the requested interface.
  257. * ppvOut out Returned interface pointer.
  258. *
  259. * Returns:
  260. * S_OK or E_NOINTERFACE.
  261. */
  262. STDMETHODIMP EXOA::EXOA_UNK::QueryInterface(REFIID riid, LPVOID * ppvOut)
  263. {
  264. // We need to preserve object identity when IUnknown is requested.
  265. if (IID_IUnknown == riid)
  266. {
  267. *ppvOut = this;
  268. AddRef();
  269. return S_OK;
  270. }
  271. return m_pexoa->InternalQueryInterface(riid, ppvOut);
  272. }
  273. /*
  274. * EXOA::EXOA_UNK::AddRef
  275. *
  276. * Purpose:
  277. * Increases the reference count on the object, by deferring
  278. * to EXO::AddRef(). Note that we're _not_ calling EXOA::Addref()
  279. * as that would release the refcount of the aggregate, not this
  280. * object.
  281. *
  282. * Arguments:
  283. * None.
  284. *
  285. * Returns:
  286. * The new reference count.
  287. */
  288. STDMETHODIMP_(ULONG) EXOA::EXOA_UNK::AddRef()
  289. {
  290. return m_pexoa->InternalAddRef();
  291. }
  292. /*
  293. * EXOA::EXOA_UNK::Release
  294. *
  295. * Purpose:
  296. * Decreases the reference count on the object, by deferring
  297. * to EXO::Release(). Note that we're _not_ calling EXOA::Release()
  298. * as that would release the refcount of the aggregate, not this
  299. * object.
  300. *
  301. * Arguments:
  302. * None.
  303. *
  304. * Returns:
  305. * The new reference count.
  306. */
  307. STDMETHODIMP_(ULONG) EXOA::EXOA_UNK::Release()
  308. {
  309. return m_pexoa->InternalRelease();
  310. }
  311. // Implementation of EXOA methods ////////////////////////////////////////
  312. EXOA::EXOA(IUnknown * punkOuter)
  313. {
  314. m_exoa_unk.m_pexoa = this;
  315. m_punkOuter = (punkOuter) ? punkOuter : &m_exoa_unk;
  316. }
  317. EXOA::~EXOA()
  318. { // must have this or linker whines.
  319. }
  320. // end of exo.cpp ////////////////////////////////////////