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

/*
* e x o . h
*
* Purpose:
* Base Exchange COM Object
*
* Any Exchange object that implements one or more COM interfaces
* should derive from EXObject and create an interface table
* using the macros below.
*
* Originator:
* JohnKal
* Owner:
* BeckyAn
*
* Copyright (C) Microsoft Corp 1993-1997. All rights reserved.
*/
//
// How to use the macros (overview).
// You need to do three things:
// Declare your class.
// Route your IUnknown processing to EXO.
// Fill in EXO's data structures.
//
// When declaring your class, you must:
// Inherit from EXO.
//
// To route your IUnknown processing to EXO:
// Put the EXO[A]_INCLASS_DECL macro in the PUBLIC part of your class.
// NOTE: This also declares the EXO static data in your class.
//
// When filling in EXO's data structures:
// In some source-file, build an interface mapping table.
// BEGIN_INTERFACE_TABLE
// INTERFACE_MAP
// END_INTERFACE_TABLE
// In the same source-file, after the interface mapping table,
// declare & fill in the EXO class info structure.
// EXO[A]_GLOBAL_DATA_DECL
//
// Quick example:
//
/*
In snacks.h
class CSnackBag: public EXO, public IFiddle, public IFaddle
{
public:
EXO_INCLASS_DECL(CSnackBag);
// IFiddle methods
// IFaddle methods
protected:
// protected methods & data
private:
// private methods & data
};
In snacks.cpp
BEGIN_INTERFACE_TABLE(CSnackBag)
INTERFACE_MAP(CSnackBag, IFiddle),
INTERFACE_MAP(CSnackBag, IFaddle)
END_INTERFACE_TABLE(CSnackBag);
EXO_GLOBAL_DATA_DECL(CSnackBag, EXO);
*/
//
//
#ifndef __exo_h_
#define __exo_h_
// Macros EXO needs ////////////////////////////////////////
// NOTE: All are named to avoid local name collisions, for your shopping convenience!
// Compute the offset to 'this' (of a specific type) when it's cast from one
// interface to another. (concept: punk = (intf2) (intf1) (class) pobj --
// casting pobj, an instance of class, "from" intf1 "to" intf2.)
// We use them to get the offset from EXO (who is doing all the real work)
// to another interface in a particular class.
// NOTE: This is done in two steps because the compiler (VC5.0) was unable
// to figure out the math at compile-time when we subtracted one from the other.
// These values are used to initialize our static tables, and we don't
// want to explicitly call CRT_INIT just to get a few offsets. So use two steps.
// (To get back to one step, combine these two steps as in ApplyDbCast, Down - Up).
// To is the delta of intf2 ("to") in cls. From is the delta of intf1 ("from").
//
// NOTE: The 0x1000 for the pointer seems weird, but that is randomly chosen
// value and the thing we are interested in is the difference between the values
// of return from EXODbCastTo (IIDINFO::cbDown) and EXODbCastFrom (IIDINFO::cbUp).
//
#define EXODbCastTo(_cls, _intf1, _intf2) ((ULONG_PTR)static_cast<_intf2 *>(static_cast<_cls *>((void *)0x1000)))
#define EXODbCastFrom(_cls, _intf1, _intf2) ((ULONG_PTR)static_cast<_intf1 *>(static_cast<_cls *>((void *)0x1000)))
// apply that offset since the base class can't do it automagically
#define EXOApplyDbCast(_intf, _pobj, _cbTo, _cbFrom) ((_intf *)((BYTE *)_pobj + _cbTo - _cbFrom))
// Gives the count of elements in an array
#define EXOCElems(_rg) (sizeof(_rg)/sizeof(_rg[0]))
// EXO is an abstract base class. Since you can't instantiate him directly,
// he doesn't need his vtable pointers set in the ctor/dtor. (And he
// promises not to do ANYTHING in his ctor/dtor that could cause a virtual
// function to be called). So if we have a supporting MS C-compiler,
// turn off his vtables.
#if _MSC_VER<1100
#define EXO_NO_VTABLE
#else // _MSC_VER check
#ifdef _EXO_DISABLE_NO_VTABLE
#define EXO_NO_VTABLE
#else // !_EXODISABLE_NO_VTABLE
#define EXO_NO_VTABLE __declspec(novtable)
#endif // _EXO_DISABLE_NO_VTABLE
#endif // _MSC_VER check
// Global flag to turn on/off the EXO debug tracing.
#ifdef DBG
extern BOOL g_fExoDebugTraceOn;
#endif // DBG
// Interface map ////////////////////////////////////////
/*
* IIDINFO -- Interface ID (IID) INFOrmation
*
* Contains a list of interfaces and offsets to convert an EXO-derived
* object pointer to that interface.
*/
typedef struct // Information about interfaces.
{
LPIID iid; // Interface ID.
ULONG_PTR cbDown; // offset of interface from beginning
ULONG_PTR cbUp; // of object.
#ifdef DBG
LPTSTR szIntfName; // Interface name
#endif // DBG
} IIDINFO;
// Macros for the name of a class's interface mapping table.
#define INTERFACE_TABLE(_cls) _cls ## ::c_rgiidinfo
#define DECLARE_INTERFACE_TABLE_INCLASS(_cls) static const IIDINFO c_rgiidinfo[]
// Helper macros to fill in the interface mapping table.
#ifdef DBG
#define INTERFACE_MAP_EX(_cl, _iid, _intf) \
{ (LPIID) & _iid, EXODbCastTo(_cl, EXO, _intf), EXODbCastFrom(_cl, EXO, _intf), TEXT(# _intf) }
#else // !DBG
#define INTERFACE_MAP_EX(_cl, _iid, _intf) \
{ (LPIID) & _iid, EXODbCastTo(_cl, EXO, _intf), EXODbCastFrom(_cl, EXO, _intf) }
#endif // DBG else
// Macros to actually fill in the interface mapping table.
//
// Use the BEGIN_INTERFACE_TABLE macro to start a table definition.
// Use the INTERFACE_MAP macro to express support for standard interfaces.
// These should be interfaces which, when prepended by IID_, yield a valid
// IID name. If you are doing advanced hackery, use the INTERFACE_MAP_EX
// macro instead. It allows you more control over which IID_ gets mapped
// to which interface.
// Use the END_INTERFACE_TABLE macro to end your table definition.
//
// NOTE: It is assumed that the very first interface of any non-aggregated
// class derived from EXO does double work as its IUnknown interface. This
// explains the '0' offset next to IID_IUnknown in the BEGIN_INTERFACE_TABLE
// macro below.
#ifdef DBG
#define BEGIN_INTERFACE_TABLE(_cl) \
const IIDINFO INTERFACE_TABLE(_cl)[] = \
{ \
{ (LPIID) & IID_IUnknown, 0, 0, TEXT("IUnknown") },
#else // DBG
#define BEGIN_INTERFACE_TABLE(_cl) \
const IIDINFO INTERFACE_TABLE(_cl)[] = \
{ \
{ (LPIID) & IID_IUnknown, 0, 0 },
#endif // DBG, else
#define INTERFACE_MAP(_cl, _intf) \
INTERFACE_MAP_EX(_cl, IID_ ## _intf, _intf)
#define END_INTERFACE_TABLE(_cl) \
}
#ifdef EXO_CLASSFACTORY_ENABLED
// EXchange Object TYPes
// To be used with a general-purpose class factory. These types
// can be used to check if a class needs special support in the DLL's
// self-registration (DllRegisterServer) routine.
enum {
exotypNull = 0, // invalid value
exotypAutomation, // OLE automation object derived from CAutomationObject
exotypControl, // ActiveX control derived from CInternetControl or COleControl
exotypPropPage, // property page derived from CPropertyPage
exotypNonserver, // not registered as an OLE server
};
// EXO prototype for a named constructor. For use with a general-purpose
// class factory.
typedef HRESULT (* PFNEXOCLSINFO)(const struct _exoclsinfo *pxci, LPUNKNOWN punkOuter,
REFIID riid, LPVOID *ppvOut);
#endif // EXO_CLASSFACTORY_ENABLED
/*
* EXOCLSINFO -- EXchange Object CLaSs INFOrmation.
*
* This structure contains all the constant class information of a
* particular class. This includes the interface mapping table
* (IIDINFO count and array) and a pointer to the parent class's
* EXOCLSINFO structure. These items are used by EXO's base implementation
* of QueryInterface. The parent class here must be a subclass of EXO,
* or EXO itself if this class derives directly from EXO. Thus these
* structures make a traceable chain of inforamtion back up to EXO, the root.
* For debugging purposes, a stringized version of the class name is included.
* In support of a general-purpose class factory, additional information,
* such as the CLSID and a standard creation function can be included.
*/
typedef struct _exoclsinfo
{
UINT ciidinfo; // Count of interfaces this class supports.
const IIDINFO * rgiidinfo; // Info for interfaces this class supports.
const _exoclsinfo * pexoclsinfoParent; // Parent's EXOCLSINFO structure.
#ifdef DBG
LPTSTR szClassName; // Class name -- for debug purposes.
#endif // DBG
#ifdef EXO_CLASSFACTORY_ENABLED
// Data to use with a general, multi-class class factory.
int exotyp; // type of the object
const CLSID * pclsid; // CLaSs ID (NULL if not co-creatable)
PFNEXOCLSINFO HrCreate; // Function to create an object of this class.
#endif // EXO_CLASSFACTORY_ENABLED
} EXOCLSINFO;
// Macros for the name of a class's exoclsinfo.
#define EXOCLSINFO_NAME(_cls) _cls ## ::c_exoclsinfo
#define DECLARE_EXOCLSINFO(_cls) const EXOCLSINFO EXOCLSINFO_NAME(_cls)
#define DECLARE_EXOCLSINFO_INCLASS(_cls) static const EXOCLSINFO c_exoclsinfo
// Helper macros to fill in the exoclsinfo.
#ifdef EXO_CLASSFACTORY_ENABLED
#ifdef DBG
#define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
{ EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
(_iidinfoparent), TEXT( #_cls ), \
(_exotyp), (LPCLSID) (_pclsid), (_pfn) } \
#else // !DBG
#define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
{ EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
(_iidinfoparent), \
(_exotyp), (LPCLSID) (_pclsid), (_pfn) } \
#endif // DBG, else
#else // !EXO_CLASSFACTORY_ENABLED
#ifdef DBG
#define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
{ EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
(_iidinfoparent), TEXT( #_cls ) }
#else // !DBG
#define EXOCLSINFO_CONTENT_EX(_cls, _iidinfoparent, _exotyp, _pclsid, _pfn) \
{ EXOCElems(INTERFACE_TABLE(_cls)), INTERFACE_TABLE(_cls), \
(_iidinfoparent), }
#endif // DBG, else
#endif // EXO_CLASSFACTORY_ENABLED
// Macro to actually fill in the exoclsinfo.
#define EXOCLSINFO_CONTENT(_cls, _clsparent) \
EXOCLSINFO_CONTENT_EX( _cls, &EXOCLSINFO_NAME(_clsparent), \
exotypNonserver, &CLSID_NULL, NULL )
// Macros to access members in the exoclsinfo structure.
#ifdef DBG
#define NAMEOFOBJECT(_pexoclsinfo) (((EXOCLSINFO *)(_pexoclsinfo))->szClassName)
#endif // DBG
#ifdef EXO_CLASSFACTORY_ENABLED
#define CLSIDOFOBJECT(_pexoclsinfo) (*(((EXOCLSINFO *)(_pexoclsinfo))->pclsid))
#define CREATEFNOFOBJECT(_pexoclsinfo) (((EXOCLSINFO *)(_pexoclsinfo))->HrCreate)
#endif // EXO_CLASSFACTORY_ENABLED
// EXO and EXOA declarations ////////////////////////////////////////
/*
* EXO is the base class of Exchange objects that present one or
* more COM interfaces. To derive from EXO, follow the example
* below:
*
* class MyClass : public EXO, public ISomeInterface1, public ISomeInterface2
* {
* public:
* EXO_INCLASS_DECL(MyClass);
*
* methods for ISomeInterface1
* methods for ISomeInterface2
*
* protected:
* protected member functions & variables
*
* private:
* private member functions & variables
* };
*
*
* DISCLAIMER: currently EXO inherits from IUnknown to prevent
* maintainability problems that would show up if
* (void *) pexo != (void *) (IUnknown *) pexo. Yes, this means
* 12 extra bytes in our vtable. Those extra bytes are worth it
* (and we already had a vtable -- pure virt. dtor!). Go deal.
*/
class EXO_NO_VTABLE EXO : public IUnknown
{
public:
// Declare EXO's support structures.
DECLARE_INTERFACE_TABLE_INCLASS(EXO);
DECLARE_EXOCLSINFO_INCLASS(EXO);
protected:
// Making the constructor protected prevents people from making these
// objects on the stack. The pure virtual destructor forces derived
// classes to implement their own dtors, and prevents instances of
// EXObject from being created directly. Of course, a derived class
// may want to allow the creation of instances on the stack. It is
// up to such derived classes to make their own constructors public.
EXO();
virtual ~EXO() = 0; // pure virtual destructor
// forces derived classes to
// implement their own dtors.
// InternalQueryInterface() does the QI work for all for interfaces
// supported by this class (directly and from a child aggregate).
// Your class should route its QI work to this call using
// EXO[A]_INCLASS_DECL 99.9% of the time.
// Only override this if you have AGGREGATED another object and want to
// get them in on the action. And even then, make sure to call
// this method, EXO::InternalQueryInterface, directly before searching
// your aggregatee (kid) This is YOUR base QI!!
// See the EXO implementation of this function for more important details.
virtual HRESULT InternalQueryInterface(REFIID riid, LPVOID * ppvOut);
// InternalAddRef() & InternalRelease() do the AddRef & Release work
// for all descendents of EXO. You should ALWAYS (100% of the time)
// route AddRef/Release work to these functions.
ULONG InternalAddRef();
ULONG InternalRelease();
// Virtual function to grab the correct lowest-level exoclsinfo struct.
// All descendants who introduce a new interface (and thus have a new
// interface mapping table) should implement this method (and pass back
// an appropriately-chained exoclsinfo struct!) using one of these
// macros: Iff you are an aggregator DECLARE_GETCLSINFO. Otherwise,
// EXO[A]_INCLASS_DECL will do the right stuff for you.
virtual const EXOCLSINFO * GetEXOClassInfo() = 0;
// Again, pure virtual to force derived classes to
// implement their own before they can be instantiated.
// Our reference counter.
LONG m_cRef;
};
/*
* EXOA is the base class of Exchange objects that support being aggregated
* (in addition to having other OLE interfaces). To derive from EXOA, follow
* the example below:
*
* class MyClass : public EXOA, public ISomeInterface1, public ISomeInterface2
* {
* public:
* EXOA_INCLASS_DECL(MyClass);
*
* methods for ISomeInterface1
* methods for ISomeInterface2
*
* protected:
* protected member functions & variables
*
* private:
* private member functions & variables
* };
*/
class EXO_NO_VTABLE EXOA : public EXO
{
protected:
// The following 3 methods are not virtual, so don't get into a tiff.
HRESULT DeferQueryInterface(REFIID riid, LPVOID * ppvOut)
{return m_punkOuter->QueryInterface(riid, ppvOut);}
ULONG DeferAddRef(void)
{return m_punkOuter->AddRef();}
ULONG DeferRelease(void)
{return m_punkOuter->Release();}
// Making the constructor protected prevents people from making these
// objects on the stack. The pure virtual destructor forces derived
// classes to implement their own dtors, and prevents instances of
// EXOA from being created directly. Of course, a derived class
// may want to allow the creation of instances on the stack. It is
// up to such derived classes to make their own constructors public.
EXOA(IUnknown * punkOuter);
virtual ~EXOA() = 0; // pure virtual destructor
// forces derived classes to
// implement their own dtors.
IUnknown * m_punkOuter;
IUnknown * PunkPrivate(void) {return &m_exoa_unk;}
private:
class EXOA_UNK : public IUnknown
{
public:
STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvOut);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
public:
EXOA * m_pexoa;
};
friend class EXOA_UNK;
EXOA_UNK m_exoa_unk;
};
// Macros to properly route IUnknown calls //////////////////////////
// (Macros are your friends!) ///////////////////////////////////////
// This routes the IUnknown calls for an EXO-derived object properly.
#define DECLARE_EXO_IUNKNOWN(_cls) \
STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvOut) \
{return _cls::InternalQueryInterface(riid, ppvOut);} \
STDMETHOD_(ULONG, AddRef)(void) \
{return EXO::InternalAddRef();} \
STDMETHOD_(ULONG, Release)(void) \
{return EXO::InternalRelease();} \
// If you are an aggregator (you have aggregatee kids),
// use this macro to override EXO's InternalQueryInterface
// and call your kids there.
#define OVERRIDE_EXO_INTERNALQUREYINTERFACE \
HRESULT InternalQueryInterface(REFIID, LPVOID * ppvOut)
// This routes the IUnknown calls for an EXOA-derived object properly.
#define DECLARE_EXOA_IUNKNOWN(_cls) \
STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvOut) \
{return EXOA::DeferQueryInterface(riid, ppvOut);} \
STDMETHOD_(ULONG, AddRef)(void) \
{return EXOA::DeferAddRef();} \
STDMETHOD_(ULONG, Release)(void) \
{return EXOA::DeferRelease();} \
// Macro to implement GetEXOClassInfo & give back a pointer to the
// a correctly-chained classinfo struct.
#define DECLARE_GETCLSINFO(_cls) \
const EXOCLSINFO * GetEXOClassInfo() { return &c_exoclsinfo; }
// Here are the simple macros to use ///////////////////
// Use these in your class to declare the class's EXO data and
// to implement the properly-deferring IUnknown.
#define EXO_INCLASS_DECL(_cls) \
DECLARE_EXO_IUNKNOWN(_cls) \
DECLARE_GETCLSINFO(_cls); \
DECLARE_INTERFACE_TABLE_INCLASS(_cls); \
DECLARE_EXOCLSINFO_INCLASS(_cls)
#define EXOA_INCLASS_DECL(_cls) \
DECLARE_EXOA_IUNKNOWN(_cls) \
DECLARE_GETCLSINFO(_cls); \
DECLARE_INTERFACE_TABLE_INCLASS(_cls); \
DECLARE_EXOCLSINFO_INCLASS(_cls)
// Use these in your implementation file to define (declare space
// for the data AND fill it in) the class's EXO data.
// NOTE: These must come after your interface table declaration.
// NOTE: The parent listed here must be in the chain between you and EXO.
#define EXO_GLOBAL_DATA_DECL(_cls, _clsparent) \
DECLARE_EXOCLSINFO(_cls) = \
EXOCLSINFO_CONTENT(_cls, _clsparent)
#define EXOA_GLOBAL_DATA_DECL(_cls, _clsparent) \
EXO_GLOBAL_DATA_DECL(_cls, _clsparent)
#endif // !__exo_h_
// end of exo.h ////////////////////////////////////////