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.

525 lines
18 KiB

  1. /*
  2. * e x o . h
  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 and create an interface table
  9. * using the macros below.
  10. *
  11. * Originator:
  12. * JohnKal
  13. * Owner:
  14. * BeckyAn
  15. *
  16. * Copyright (C) Microsoft Corp 1993-1997. All rights reserved.
  17. */
  18. //
  19. // How to use the macros (overview).
  20. // You need to do three things:
  21. // Declare your class.
  22. // Route your IUnknown processing to EXO.
  23. // Fill in EXO's data structures.
  24. //
  25. // When declaring your class, you must:
  26. // Inherit from EXO.
  27. //
  28. // To route your IUnknown processing to EXO:
  29. // Put the EXO[A]_INCLASS_DECL macro in the PUBLIC part of your class.
  30. // NOTE: This also declares the EXO static data in your class.
  31. //
  32. // When filling in EXO's data structures:
  33. // In some source-file, build an interface mapping table.
  34. // BEGIN_INTERFACE_TABLE
  35. // INTERFACE_MAP
  36. // END_INTERFACE_TABLE
  37. // In the same source-file, after the interface mapping table,
  38. // declare & fill in the EXO class info structure.
  39. // EXO[A]_GLOBAL_DATA_DECL
  40. //
  41. // Quick example:
  42. //
  43. /*
  44. In snacks.h
  45. class CSnackBag: public EXO, public IFiddle, public IFaddle
  46. {
  47. public:
  48. EXO_INCLASS_DECL(CSnackBag);
  49. // IFiddle methods
  50. // IFaddle methods
  51. protected:
  52. // protected methods & data
  53. private:
  54. // private methods & data
  55. };
  56. In snacks.cpp
  57. BEGIN_INTERFACE_TABLE(CSnackBag)
  58. INTERFACE_MAP(CSnackBag, IFiddle),
  59. INTERFACE_MAP(CSnackBag, IFaddle)
  60. END_INTERFACE_TABLE(CSnackBag);
  61. EXO_GLOBAL_DATA_DECL(CSnackBag, EXO);
  62. */
  63. //
  64. //
  65. #ifndef __exo_h_
  66. #define __exo_h_
  67. // Macros EXO needs ////////////////////////////////////////
  68. // NOTE: All are named to avoid local name collisions, for your shopping convenience!
  69. // Compute the offset to 'this' (of a specific type) when it's cast from one
  70. // interface to another. (concept: punk = (intf2) (intf1) (class) pobj --
  71. // casting pobj, an instance of class, "from" intf1 "to" intf2.)
  72. // We use them to get the offset from EXO (who is doing all the real work)
  73. // to another interface in a particular class.
  74. // NOTE: This is done in two steps because the compiler (VC5.0) was unable
  75. // to figure out the math at compile-time when we subtracted one from the other.
  76. // These values are used to initialize our static tables, and we don't
  77. // want to explicitly call CRT_INIT just to get a few offsets. So use two steps.
  78. // (To get back to one step, combine these two steps as in ApplyDbCast, Down - Up).
  79. // To is the delta of intf2 ("to") in cls. From is the delta of intf1 ("from").
  80. //
  81. // NOTE: The 0x1000 for the pointer seems weird, but that is randomly chosen
  82. // value and the thing we are interested in is the difference between the values
  83. // of return from EXODbCastTo (IIDINFO::cbDown) and EXODbCastFrom (IIDINFO::cbUp).
  84. //
  85. #define EXODbCastTo(_cls, _intf1, _intf2) ((ULONG_PTR)static_cast<_intf2 *>(static_cast<_cls *>((void *)0x1000)))
  86. #define EXODbCastFrom(_cls, _intf1, _intf2) ((ULONG_PTR)static_cast<_intf1 *>(static_cast<_cls *>((void *)0x1000)))
  87. // apply that offset since the base class can't do it automagically
  88. #define EXOApplyDbCast(_intf, _pobj, _cbTo, _cbFrom) ((_intf *)((BYTE *)_pobj + _cbTo - _cbFrom))
  89. // Gives the count of elements in an array
  90. #define EXOCElems(_rg) (sizeof(_rg)/sizeof(_rg[0]))
  91. // EXO is an abstract base class. Since you can't instantiate him directly,
  92. // he doesn't need his vtable pointers set in the ctor/dtor. (And he
  93. // promises not to do ANYTHING in his ctor/dtor that could cause a virtual
  94. // function to be called). So if we have a supporting MS C-compiler,
  95. // turn off his vtables.
  96. #if _MSC_VER<1100
  97. #define EXO_NO_VTABLE
  98. #else // _MSC_VER check
  99. #ifdef _EXO_DISABLE_NO_VTABLE
  100. #define EXO_NO_VTABLE
  101. #else // !_EXODISABLE_NO_VTABLE
  102. #define EXO_NO_VTABLE __declspec(novtable)
  103. #endif // _EXO_DISABLE_NO_VTABLE
  104. #endif // _MSC_VER check
  105. // Global flag to turn on/off the EXO debug tracing.
  106. #ifdef DBG
  107. extern BOOL g_fExoDebugTraceOn;
  108. #endif // DBG
  109. // Interface map ////////////////////////////////////////
  110. /*
  111. * IIDINFO -- Interface ID (IID) INFOrmation
  112. *
  113. * Contains a list of interfaces and offsets to convert an EXO-derived
  114. * object pointer to that interface.
  115. */
  116. typedef struct // Information about interfaces.
  117. {
  118. LPIID iid; // Interface ID.
  119. ULONG_PTR cbDown; // offset of interface from beginning
  120. ULONG_PTR cbUp; // of object.
  121. #ifdef DBG
  122. LPTSTR szIntfName; // Interface name
  123. #endif // DBG
  124. } IIDINFO;
  125. // Macros for the name of a class's interface mapping table.
  126. #define INTERFACE_TABLE(_cls) _cls ## ::c_rgiidinfo
  127. #define DECLARE_INTERFACE_TABLE_INCLASS(_cls) static const IIDINFO c_rgiidinfo[]
  128. // Helper macros to fill in the interface mapping table.
  129. #ifdef DBG
  130. #define INTERFACE_MAP_EX(_cl, _iid, _intf) \
  131. { (LPIID) & _iid, EXODbCastTo(_cl, EXO, _intf), EXODbCastFrom(_cl, EXO, _intf), TEXT(# _intf) }
  132. #else // !DBG
  133. #define INTERFACE_MAP_EX(_cl, _iid, _intf) \
  134. { (LPIID) & _iid, EXODbCastTo(_cl, EXO, _intf), EXODbCastFrom(_cl, EXO, _intf) }
  135. #endif // DBG else
  136. // Macros to actually fill in the interface mapping table.
  137. //
  138. // Use the BEGIN_INTERFACE_TABLE macro to start a table definition.
  139. // Use the INTERFACE_MAP macro to express support for standard interfaces.
  140. // These should be interfaces which, when prepended by IID_, yield a valid
  141. // IID name. If you are doing advanced hackery, use the INTERFACE_MAP_EX
  142. // macro instead. It allows you more control over which IID_ gets mapped
  143. // to which interface.
  144. // Use the END_INTERFACE_TABLE macro to end your table definition.
  145. //
  146. // NOTE: It is assumed that the very first interface of any non-aggregated
  147. // class derived from EXO does double work as its IUnknown interface. This
  148. // explains the '0' offset next to IID_IUnknown in the BEGIN_INTERFACE_TABLE
  149. // macro below.
  150. #ifdef DBG
  151. #define BEGIN_INTERFACE_TABLE(_cl) \
  152. const IIDINFO INTERFACE_TABLE(_cl)[] = \
  153. { \
  154. { (LPIID) & IID_IUnknown, 0, 0, TEXT("IUnknown") },
  155. #else // DBG
  156. #define BEGIN_INTERFACE_TABLE(_cl) \
  157. const IIDINFO INTERFACE_TABLE(_cl)[] = \
  158. { \
  159. { (LPIID) & IID_IUnknown, 0, 0 },
  160. #endif // DBG, else
  161. #define INTERFACE_MAP(_cl, _intf) \
  162. INTERFACE_MAP_EX(_cl, IID_ ## _intf, _intf)
  163. #define END_INTERFACE_TABLE(_cl) \
  164. }
  165. #ifdef EXO_CLASSFACTORY_ENABLED
  166. // EXchange Object TYPes
  167. // To be used with a general-purpose class factory. These types
  168. // can be used to check if a class needs special support in the DLL's
  169. // self-registration (DllRegisterServer) routine.
  170. enum {
  171. exotypNull = 0, // invalid value
  172. exotypAutomation, // OLE automation object derived from CAutomationObject
  173. exotypControl, // ActiveX control derived from CInternetControl or COleControl
  174. exotypPropPage, // property page derived from CPropertyPage
  175. exotypNonserver, // not registered as an OLE server
  176. };
  177. // EXO prototype for a named constructor. For use with a general-purpose
  178. // class factory.
  179. typedef HRESULT (* PFNEXOCLSINFO)(const struct _exoclsinfo *pxci, LPUNKNOWN punkOuter,
  180. REFIID riid, LPVOID *ppvOut);
  181. #endif // EXO_CLASSFACTORY_ENABLED
  182. /*
  183. * EXOCLSINFO -- EXchange Object CLaSs INFOrmation.
  184. *
  185. * This structure contains all the constant class information of a
  186. * particular class. This includes the interface mapping table
  187. * (IIDINFO count and array) and a pointer to the parent class's
  188. * EXOCLSINFO structure. These items are used by EXO's base implementation
  189. * of QueryInterface. The parent class here must be a subclass of EXO,
  190. * or EXO itself if this class derives directly from EXO. Thus these
  191. * structures make a traceable chain of inforamtion back up to EXO, the root.
  192. * For debugging purposes, a stringized version of the class name is included.
  193. * In support of a general-purpose class factory, additional information,
  194. * such as the CLSID and a standard creation function can be included.
  195. */
  196. typedef struct _exoclsinfo
  197. {
  198. UINT ciidinfo; // Count of interfaces this class supports.
  199. const IIDINFO * rgiidinfo; // Info for interfaces this class supports.
  200. const _exoclsinfo * pexoclsinfoParent; // Parent's EXOCLSINFO structure.
  201. #ifdef DBG
  202. LPTSTR szClassName; // Class name -- for debug purposes.
  203. #endif // DBG
  204. #ifdef EXO_CLASSFACTORY_ENABLED
  205. // Data to use with a general, multi-class class factory.
  206. int exotyp; // type of the object
  207. const CLSID * pclsid; // CLaSs ID (NULL if not co-creatable)
  208. PFNEXOCLSINFO HrCreate; // Function to create an object of this class.
  209. #endif // EXO_CLASSFACTORY_ENABLED
  210. } EXOCLSINFO;
  211. // Macros for the name of a class's exoclsinfo.
  212. #define EXOCLSINFO_NAME(_cls) _cls ## ::c_exoclsinfo
  213. #define DECLARE_EXOCLSINFO(_cls) const EXOCLSINFO EXOCLSINFO_NAME(_cls)
  214. #define DECLARE_EXOCLSINFO_INCLASS(_cls) static const EXOCLSINFO c_exoclsinfo
  215. // Helper macros to fill in the exoclsinfo.
  216. #ifdef EXO_CLASSFACTORY_ENABLED
  217. #ifdef DBG
  218. #define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
  219. { EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
  220. (_iidinfoparent), TEXT( #_cls ), \
  221. (_exotyp), (LPCLSID) (_pclsid), (_pfn) } \
  222. #else // !DBG
  223. #define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
  224. { EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
  225. (_iidinfoparent), \
  226. (_exotyp), (LPCLSID) (_pclsid), (_pfn) } \
  227. #endif // DBG, else
  228. #else // !EXO_CLASSFACTORY_ENABLED
  229. #ifdef DBG
  230. #define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
  231. { EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
  232. (_iidinfoparent), TEXT( #_cls ) }
  233. #else // !DBG
  234. #define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
  235. { EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
  236. (_iidinfoparent), }
  237. #endif // DBG, else
  238. #endif // EXO_CLASSFACTORY_ENABLED
  239. // Macro to actually fill in the exoclsinfo.
  240. #define EXOCLSINFO_CONTENT(_cls, _clsparent) \
  241. EXOCLSINFO_CONTENT_EX( _cls, &EXOCLSINFO_NAME(_clsparent), \
  242. exotypNonserver, &CLSID_NULL, NULL )
  243. // Macros to access members in the exoclsinfo structure.
  244. #ifdef DBG
  245. #define NAMEOFOBJECT(_pexoclsinfo) (((EXOCLSINFO *)(_pexoclsinfo))->szClassName)
  246. #endif // DBG
  247. #ifdef EXO_CLASSFACTORY_ENABLED
  248. #define CLSIDOFOBJECT(_pexoclsinfo) (*(((EXOCLSINFO *)(_pexoclsinfo))->pclsid))
  249. #define CREATEFNOFOBJECT(_pexoclsinfo) (((EXOCLSINFO *)(_pexoclsinfo))->HrCreate)
  250. #endif // EXO_CLASSFACTORY_ENABLED
  251. // EXO and EXOA declarations ////////////////////////////////////////
  252. /*
  253. * EXO is the base class of Exchange objects that present one or
  254. * more COM interfaces. To derive from EXO, follow the example
  255. * below:
  256. *
  257. * class MyClass : public EXO, public ISomeInterface1, public ISomeInterface2
  258. * {
  259. * public:
  260. * EXO_INCLASS_DECL(MyClass);
  261. *
  262. * methods for ISomeInterface1
  263. * methods for ISomeInterface2
  264. *
  265. * protected:
  266. * protected member functions & variables
  267. *
  268. * private:
  269. * private member functions & variables
  270. * };
  271. *
  272. *
  273. * DISCLAIMER: currently EXO inherits from IUnknown to prevent
  274. * maintainability problems that would show up if
  275. * (void *) pexo != (void *) (IUnknown *) pexo. Yes, this means
  276. * 12 extra bytes in our vtable. Those extra bytes are worth it
  277. * (and we already had a vtable -- pure virt. dtor!). Go deal.
  278. */
  279. class EXO_NO_VTABLE EXO : public IUnknown
  280. {
  281. public:
  282. // Declare EXO's support structures.
  283. DECLARE_INTERFACE_TABLE_INCLASS(EXO);
  284. DECLARE_EXOCLSINFO_INCLASS(EXO);
  285. protected:
  286. // Making the constructor protected prevents people from making these
  287. // objects on the stack. The pure virtual destructor forces derived
  288. // classes to implement their own dtors, and prevents instances of
  289. // EXObject from being created directly. Of course, a derived class
  290. // may want to allow the creation of instances on the stack. It is
  291. // up to such derived classes to make their own constructors public.
  292. EXO();
  293. virtual ~EXO() = 0; // pure virtual destructor
  294. // forces derived classes to
  295. // implement their own dtors.
  296. // InternalQueryInterface() does the QI work for all for interfaces
  297. // supported by this class (directly and from a child aggregate).
  298. // Your class should route its QI work to this call using
  299. // EXO[A]_INCLASS_DECL 99.9% of the time.
  300. // Only override this if you have AGGREGATED another object and want to
  301. // get them in on the action. And even then, make sure to call
  302. // this method, EXO::InternalQueryInterface, directly before searching
  303. // your aggregatee (kid) This is YOUR base QI!!
  304. // See the EXO implementation of this function for more important details.
  305. virtual HRESULT InternalQueryInterface(REFIID riid, LPVOID * ppvOut);
  306. // InternalAddRef() & InternalRelease() do the AddRef & Release work
  307. // for all descendents of EXO. You should ALWAYS (100% of the time)
  308. // route AddRef/Release work to these functions.
  309. ULONG InternalAddRef();
  310. ULONG InternalRelease();
  311. // Virtual function to grab the correct lowest-level exoclsinfo struct.
  312. // All descendants who introduce a new interface (and thus have a new
  313. // interface mapping table) should implement this method (and pass back
  314. // an appropriately-chained exoclsinfo struct!) using one of these
  315. // macros: Iff you are an aggregator DECLARE_GETCLSINFO. Otherwise,
  316. // EXO[A]_INCLASS_DECL will do the right stuff for you.
  317. virtual const EXOCLSINFO * GetEXOClassInfo() = 0;
  318. // Again, pure virtual to force derived classes to
  319. // implement their own before they can be instantiated.
  320. // Our reference counter.
  321. LONG m_cRef;
  322. };
  323. /*
  324. * EXOA is the base class of Exchange objects that support being aggregated
  325. * (in addition to having other OLE interfaces). To derive from EXOA, follow
  326. * the example below:
  327. *
  328. * class MyClass : public EXOA, public ISomeInterface1, public ISomeInterface2
  329. * {
  330. * public:
  331. * EXOA_INCLASS_DECL(MyClass);
  332. *
  333. * methods for ISomeInterface1
  334. * methods for ISomeInterface2
  335. *
  336. * protected:
  337. * protected member functions & variables
  338. *
  339. * private:
  340. * private member functions & variables
  341. * };
  342. */
  343. class EXO_NO_VTABLE EXOA : public EXO
  344. {
  345. protected:
  346. // The following 3 methods are not virtual, so don't get into a tiff.
  347. HRESULT DeferQueryInterface(REFIID riid, LPVOID * ppvOut)
  348. {return m_punkOuter->QueryInterface(riid, ppvOut);}
  349. ULONG DeferAddRef(void)
  350. {return m_punkOuter->AddRef();}
  351. ULONG DeferRelease(void)
  352. {return m_punkOuter->Release();}
  353. // Making the constructor protected prevents people from making these
  354. // objects on the stack. The pure virtual destructor forces derived
  355. // classes to implement their own dtors, and prevents instances of
  356. // EXOA from being created directly. Of course, a derived class
  357. // may want to allow the creation of instances on the stack. It is
  358. // up to such derived classes to make their own constructors public.
  359. EXOA(IUnknown * punkOuter);
  360. virtual ~EXOA() = 0; // pure virtual destructor
  361. // forces derived classes to
  362. // implement their own dtors.
  363. IUnknown * m_punkOuter;
  364. IUnknown * PunkPrivate(void) {return &m_exoa_unk;}
  365. private:
  366. class EXOA_UNK : public IUnknown
  367. {
  368. public:
  369. STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvOut);
  370. STDMETHOD_(ULONG, AddRef)();
  371. STDMETHOD_(ULONG, Release)();
  372. public:
  373. EXOA * m_pexoa;
  374. };
  375. friend class EXOA_UNK;
  376. EXOA_UNK m_exoa_unk;
  377. };
  378. // Macros to properly route IUnknown calls //////////////////////////
  379. // (Macros are your friends!) ///////////////////////////////////////
  380. // This routes the IUnknown calls for an EXO-derived object properly.
  381. #define DECLARE_EXO_IUNKNOWN(_cls) \
  382. STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvOut) \
  383. {return _cls::InternalQueryInterface(riid, ppvOut);} \
  384. STDMETHOD_(ULONG, AddRef)(void) \
  385. {return EXO::InternalAddRef();} \
  386. STDMETHOD_(ULONG, Release)(void) \
  387. {return EXO::InternalRelease();} \
  388. // If you are an aggregator (you have aggregatee kids),
  389. // use this macro to override EXO's InternalQueryInterface
  390. // and call your kids there.
  391. #define OVERRIDE_EXO_INTERNALQUREYINTERFACE \
  392. HRESULT InternalQueryInterface(REFIID, LPVOID * ppvOut)
  393. // This routes the IUnknown calls for an EXOA-derived object properly.
  394. #define DECLARE_EXOA_IUNKNOWN(_cls) \
  395. STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvOut) \
  396. {return EXOA::DeferQueryInterface(riid, ppvOut);} \
  397. STDMETHOD_(ULONG, AddRef)(void) \
  398. {return EXOA::DeferAddRef();} \
  399. STDMETHOD_(ULONG, Release)(void) \
  400. {return EXOA::DeferRelease();} \
  401. // Macro to implement GetEXOClassInfo & give back a pointer to the
  402. // a correctly-chained classinfo struct.
  403. #define DECLARE_GETCLSINFO(_cls) \
  404. const EXOCLSINFO * GetEXOClassInfo() { return &c_exoclsinfo; }
  405. // Here are the simple macros to use ///////////////////
  406. // Use these in your class to declare the class's EXO data and
  407. // to implement the properly-deferring IUnknown.
  408. #define EXO_INCLASS_DECL(_cls) \
  409. DECLARE_EXO_IUNKNOWN(_cls) \
  410. DECLARE_GETCLSINFO(_cls); \
  411. DECLARE_INTERFACE_TABLE_INCLASS(_cls); \
  412. DECLARE_EXOCLSINFO_INCLASS(_cls)
  413. #define EXOA_INCLASS_DECL(_cls) \
  414. DECLARE_EXOA_IUNKNOWN(_cls) \
  415. DECLARE_GETCLSINFO(_cls); \
  416. DECLARE_INTERFACE_TABLE_INCLASS(_cls); \
  417. DECLARE_EXOCLSINFO_INCLASS(_cls)
  418. // Use these in your implementation file to define (declare space
  419. // for the data AND fill it in) the class's EXO data.
  420. // NOTE: These must come after your interface table declaration.
  421. // NOTE: The parent listed here must be in the chain between you and EXO.
  422. #define EXO_GLOBAL_DATA_DECL(_cls, _clsparent) \
  423. DECLARE_EXOCLSINFO(_cls) = \
  424. EXOCLSINFO_CONTENT(_cls, _clsparent)
  425. #define EXOA_GLOBAL_DATA_DECL(_cls, _clsparent) \
  426. EXO_GLOBAL_DATA_DECL(_cls, _clsparent)
  427. #endif // !__exo_h_
  428. // end of exo.h ////////////////////////////////////////