home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / combase.h < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-21  |  9.6 KB  |  283 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11.  
  12. // Base class hierachy for creating COM objects, December 1994
  13.  
  14. /*
  15.  
  16. a. Derive your COM object from CUnknown
  17.  
  18. b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
  19.    and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
  20.    to. The HRESULT * allows error codes to be passed around constructors and
  21.    the TCHAR * is a descriptive name that can be printed on the debugger.
  22.  
  23.    It is important that constructors only change the HRESULT * if they have
  24.    to set an ERROR code, if it was successful then leave it alone or you may
  25.    overwrite an error code from an object previously created.
  26.  
  27.    When you call a constructor the descriptive name should be in static store
  28.    as we do not copy the string. To stop large amounts of memory being used
  29.    in retail builds by all these static strings use the NAME macro,
  30.  
  31.    CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
  32.    if (FAILED(hr)) {
  33.        return hr;
  34.    }
  35.  
  36.    In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
  37.    knows not to do anything with objects that don't have a name.
  38.  
  39. c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
  40.    TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
  41.    error, or just simply pass it through to the constructor.
  42.  
  43.    The object creation will fail in the class factory if the HRESULT indicates
  44.    an error (ie FAILED(HRESULT) == TRUE)
  45.  
  46. d. Create a FactoryTemplate with your object's class id and CreateInstance
  47.    function.
  48.  
  49. Then (for each interface) either
  50.  
  51. Multiple inheritance
  52.  
  53. 1. Also derive it from ISomeInterface
  54. 2. Include DECLARE_IUNKNOWN in your class definition to declare
  55.    implementations of QueryInterface, AddRef and Release that
  56.    call the outer unknown
  57. 3. Override NonDelegatingQueryInterface to expose ISomeInterface by
  58.    code something like
  59.  
  60.      if (riid == IID_ISomeInterface) {
  61.          return GetInterface((ISomeInterface *) this, ppv);
  62.      } else {
  63.          return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  64.      }
  65.  
  66. 4. Declare and implement the member functions of ISomeInterface.
  67.  
  68. or: Nested interfaces
  69.  
  70. 1. Declare a class derived from CUnknown
  71. 2. Include DECLARE_IUNKNOWN in your class definition
  72. 3. Override NonDelegatingQueryInterface to expose ISomeInterface by
  73.    code something like
  74.  
  75.      if (riid == IID_ISomeInterface) {
  76.          return GetInterface((ISomeInterface *) this, ppv);
  77.      } else {
  78.          return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  79.      }
  80.  
  81. 4. Implement the member functions of ISomeInterface. Use GetOwner() to
  82.    access the COM object class.
  83.  
  84. And in your COM object class:
  85.  
  86. 5. Make the nested class a friend of the COM object class, and declare
  87.    an instance of the nested class as a member of the COM object class.
  88.  
  89.    NOTE that because you must always pass the outer unknown and an hResult
  90.    to the CUnknown constructor you cannot use a default constructor, in
  91.    other words you will have to make the member variable a pointer to the
  92.    class and make a NEW call in your constructor to actually create it.
  93.  
  94. 6. override the NonDelegatingQueryInterface with code like this:
  95.  
  96.      if (riid == IID_ISomeInterface) {
  97.          return m_pImplFilter->
  98.             NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
  99.      } else {
  100.          return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  101.      }
  102.  
  103. You can have mixed classes which support some interfaces via multiple
  104. inheritance and some via nested classes
  105.  
  106. */
  107.  
  108. #ifndef __COMBASE__
  109. #define __COMBASE__
  110.  
  111. /* The DLLENTRY module initialises the module handle on loading */
  112.  
  113. extern HINSTANCE g_hInst;
  114.  
  115. /* On DLL load remember which platform we are running on */
  116.  
  117. extern DWORD g_amPlatform;
  118. extern OSVERSIONINFO g_osInfo;     // Filled in by GetVersionEx
  119.  
  120. /* Version of IUnknown that is renamed to allow a class to support both
  121.    non delegating and delegating IUnknowns in the same COM object */
  122.  
  123. DECLARE_INTERFACE(INonDelegatingUnknown)
  124. {
  125.     STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
  126.     STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
  127.     STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
  128. };
  129.  
  130. typedef INonDelegatingUnknown *PNDUNKNOWN;
  131.  
  132.  
  133. /* This is the base object class that supports active object counting. As
  134.    part of the debug facilities we trace every time a C++ object is created
  135.    or destroyed. The name of the object has to be passed up through the class
  136.    derivation list during construction as you cannot call virtual functions
  137.    in the constructor. The downside of all this is that every single object
  138.    constructor has to take an object name parameter that describes it */
  139.  
  140. class CBaseObject
  141. {
  142.  
  143. private:
  144.  
  145.     // Disable the copy constructor and assignment by default so you will get
  146.     //   compiler errors instead of unexpected behaviour if you pass objects
  147.     //   by value or assign objects.
  148.     CBaseObject(const CBaseObject& objectSrc);          // no implementation
  149.     void operator=(const CBaseObject& objectSrc);       // no implementation
  150.  
  151. private:
  152.     static LONG m_cObjects;     /* Total number of objects active */
  153.  
  154. protected:
  155. #ifdef DEBUG
  156.     DWORD m_dwCookie;           /* Cookie identifying this object */
  157. #endif
  158.  
  159.  
  160. public:
  161.  
  162.     /* These increment and decrement the number of active objects */
  163.  
  164.     CBaseObject(TCHAR *pName);
  165.     ~CBaseObject();
  166.  
  167.     /* Call this to find if there are any CUnknown derived objects active */
  168.  
  169.     static LONG ObjectsActive() {
  170.         return m_cObjects;
  171.     };
  172. };
  173.  
  174.  
  175. /* An object that supports one or more COM interfaces will be based on
  176.    this class. It supports counting of total objects for DLLCanUnloadNow
  177.    support, and an implementation of the core non delegating IUnknown */
  178.  
  179. class CUnknown : public INonDelegatingUnknown,
  180.                  public CBaseObject
  181. {
  182.  
  183. private:
  184.     const LPUNKNOWN m_pUnknown; /* Owner of this object */
  185.  
  186. protected:                      /* So we can override NonDelegatingRelease() */
  187.     volatile LONG m_cRef;       /* Number of reference counts */
  188.  
  189. public:
  190.  
  191.     CUnknown(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
  192.     virtual ~CUnknown() {};
  193.  
  194.     /* Return the owner of this object */
  195.  
  196.     LPUNKNOWN GetOwner() const {
  197.         return m_pUnknown;
  198.     };
  199.  
  200.     /* Called from the class factory to create a new instance, it is
  201.        pure virtual so it must be overriden in your derived class */
  202.  
  203.     /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
  204.  
  205.     /* Non delegating unknown implementation */
  206.  
  207.     STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
  208.     STDMETHODIMP_(ULONG) NonDelegatingAddRef();
  209.     STDMETHODIMP_(ULONG) NonDelegatingRelease();
  210.  
  211.     /* Return an interface pointer to a requesting client
  212.        performing a thread safe AddRef as necessary */
  213.  
  214.     HRESULT GetInterface(LPUNKNOWN pUnk, void **ppv);
  215.  
  216.  
  217. };
  218.  
  219. /* The standard InterlockedXXX functions won't take volatiles */
  220. static inline LONG InterlockedIncrement( volatile LONG * plong )
  221. { return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
  222.  
  223. static inline LONG InterlockedDecrement( volatile LONG * plong )
  224. { return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
  225.  
  226. static inline LONG InterlockedExchange( volatile LONG * plong, LONG new_value )
  227. { return InterlockedExchange( const_cast<LONG*>( plong ), new_value ); }
  228.  
  229.  
  230. /* A function that can create a new COM object */
  231.  
  232. typedef CUnknown *(*LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
  233.  
  234. /*  A function (can be NULL) which is called from the DLL entrypoint
  235.     routine for each factory template:
  236.  
  237.     bLoading - TRUE on DLL load, FALSE on DLL unload
  238.     rclsid   - the m_ClsID of the entry
  239. */
  240. typedef void (*LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
  241.  
  242. /* Create one of these per object class in an array so that
  243.    the default class factory code can create new instances */
  244.  
  245. class CFactoryTemplate {
  246.  
  247. public:
  248.  
  249.     const WCHAR *m_Name;
  250.     const CLSID *m_ClsID;
  251.     LPFNNewCOMObject m_lpfnNew;
  252.     LPFNInitRoutine  m_lpfnInit;
  253.  
  254.     BOOL IsClassID(REFCLSID rclsid) const {
  255.         return (IsEqualCLSID(*m_ClsID,rclsid));
  256.     };
  257.  
  258.     CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
  259.         CheckPointer(phr,NULL);
  260.         return m_lpfnNew(pUnk, phr);
  261.     };
  262. };
  263.  
  264.  
  265. /* You must override the (pure virtual) NonDelegatingQueryInterface to return
  266.    interface pointers (using GetInterface) to the interfaces your derived
  267.    class supports (the default implementation only supports IUnknown) */
  268.  
  269. #define DECLARE_IUNKNOWN                                        \
  270.     STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {      \
  271.         return GetOwner()->QueryInterface(riid,ppv);            \
  272.     };                                                          \
  273.     STDMETHODIMP_(ULONG) AddRef() {                             \
  274.         return GetOwner()->AddRef();                            \
  275.     };                                                          \
  276.     STDMETHODIMP_(ULONG) Release() {                            \
  277.         return GetOwner()->Release();                           \
  278.     };
  279.  
  280. #endif /* __COMBASE__ */
  281.  
  282.  
  283.