COMBASE.H
//==========================================================================; 
// 
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
//  PURPOSE. 
// 
//  Copyright (c) 1992 - 1997  Microsoft Corporation.  All Rights Reserved. 
// 
//--------------------------------------------------------------------------; 
 
// Base class hierachy for creating COM objects, December 1994 
 
/* 
 
a. Derive your COM object from CUnknown 
 
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * 
   and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls 
   to. The HRESULT * allows error codes to be passed around constructors and 
   the TCHAR * is a descriptive name that can be printed on the debugger. 
 
   It is important that constructors only change the HRESULT * if they have 
   to set an ERROR code, if it was successful then leave it alone or you may 
   overwrite an error code from an object previously created. 
 
   When you call a constructor the descriptive name should be in static store 
   as we do not copy the string. To stop large amounts of memory being used 
   in retail builds by all these static strings use the NAME macro, 
 
   CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); 
   if (FAILED(hr)) { 
       return hr; 
   } 
 
   In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class 
   knows not to do anything with objects that don't have a name. 
 
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and 
   TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an 
   error, or just simply pass it through to the constructor. 
 
   The object creation will fail in the class factory if the HRESULT indicates 
   an error (ie FAILED(HRESULT) == TRUE) 
 
d. Create a FactoryTemplate with your object's class id and CreateInstance 
   function. 
 
Then (for each interface) either 
 
Multiple inheritance 
 
1. Also derive it from ISomeInterface 
2. Include DECLARE_IUNKNOWN in your class definition to declare 
   implementations of QueryInterface, AddRef and Release that 
   call the outer unknown 
3. Override NonDelegatingQueryInterface to expose ISomeInterface by 
   code something like 
 
     if (riid == IID_ISomeInterface) { 
         return GetInterface((ISomeInterface *) this, ppv); 
     } else { 
         return CUnknown::NonDelegatingQueryInterface(riid, ppv); 
     } 
 
4. Declare and implement the member functions of ISomeInterface. 
 
or: Nested interfaces 
 
1. Declare a class derived from CUnknown 
2. Include DECLARE_IUNKNOWN in your class definition 
3. Override NonDelegatingQueryInterface to expose ISomeInterface by 
   code something like 
 
     if (riid == IID_ISomeInterface) { 
         return GetInterface((ISomeInterface *) this, ppv); 
     } else { 
         return CUnknown::NonDelegatingQueryInterface(riid, ppv); 
     } 
 
4. Implement the member functions of ISomeInterface. Use GetOwner() to 
   access the COM object class. 
 
And in your COM object class: 
 
5. Make the nested class a friend of the COM object class, and declare 
   an instance of the nested class as a member of the COM object class. 
 
   NOTE that because you must always pass the outer unknown and an hResult 
   to the CUnknown constructor you cannot use a default constructor, in 
   other words you will have to make the member variable a pointer to the 
   class and make a NEW call in your constructor to actually create it. 
 
6. override the NonDelegatingQueryInterface with code like this: 
 
     if (riid == IID_ISomeInterface) { 
         return m_pImplFilter-> 
            NonDelegatingQueryInterface(IID_ISomeInterface, ppv); 
     } else { 
         return CUnknown::NonDelegatingQueryInterface(riid, ppv); 
     } 
 
You can have mixed classes which support some interfaces via multiple 
inheritance and some via nested classes 
 
*/ 
 
#ifndef __COMBASE__ 
#define __COMBASE__ 
 
// Filter Setup data structures no defined in axextend.idl 
 
typedef REGPINTYPES 
AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; 
 
typedef REGFILTERPINS 
AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; 
 
typedef struct _AMOVIESETUP_FILTER 
{ 
  const CLSID * clsID; 
  const WCHAR * strName; 
  DWORD      dwMerit; 
  UINT       nPins; 
  const AMOVIESETUP_PIN * lpPin; 
} 
AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; 
 
/* The DLLENTRY module initialises the module handle on loading */ 
 
extern HINSTANCE g_hInst; 
 
/* On DLL load remember which platform we are running on */ 
 
extern DWORD g_amPlatform; 
extern OSVERSIONINFO g_osInfo;     // Filled in by GetVersionEx 
 
/* Version of IUnknown that is renamed to allow a class to support both 
   non delegating and delegating IUnknowns in the same COM object */ 
 
#ifndef INONDELEGATINGUNKNOWN_DEFINED 
DECLARE_INTERFACE(INonDelegatingUnknown) 
{ 
    STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; 
    STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; 
    STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; 
}; 
#define INONDELEGATINGUNKNOWN_DEFINED 
#endif 
 
typedef INonDelegatingUnknown *PNDUNKNOWN; 
 
 
/* This is the base object class that supports active object counting. As 
   part of the debug facilities we trace every time a C++ object is created 
   or destroyed. The name of the object has to be passed up through the class 
   derivation list during construction as you cannot call virtual functions 
   in the constructor. The downside of all this is that every single object 
   constructor has to take an object name parameter that describes it */ 
 
class CBaseObject 
{ 
 
private: 
 
    // Disable the copy constructor and assignment by default so you will get 
    //   compiler errors instead of unexpected behaviour if you pass objects 
    //   by value or assign objects. 
    CBaseObject(const CBaseObject& objectSrc);          // no implementation 
    void operator=(const CBaseObject& objectSrc);       // no implementation 
 
private: 
    static LONG m_cObjects;     /* Total number of objects active */ 
 
protected: 
#ifdef DEBUG 
    DWORD m_dwCookie;           /* Cookie identifying this object */ 
#endif 
 
 
public: 
 
    /* These increment and decrement the number of active objects */ 
 
    CBaseObject(const TCHAR *pName); 
    ~CBaseObject(); 
 
    /* Call this to find if there are any CUnknown derived objects active */ 
 
    static LONG ObjectsActive() { 
        return m_cObjects; 
    }; 
}; 
 
 
/* An object that supports one or more COM interfaces will be based on 
   this class. It supports counting of total objects for DLLCanUnloadNow 
   support, and an implementation of the core non delegating IUnknown */ 
 
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, 
                 public CBaseObject 
{ 
private: 
    const LPUNKNOWN m_pUnknown; /* Owner of this object */ 
 
protected:                      /* So we can override NonDelegatingRelease() */ 
    volatile LONG m_cRef;       /* Number of reference counts */ 
 
public: 
 
    CUnknown(const TCHAR *pName, LPUNKNOWN pUnk); 
    virtual ~CUnknown() {}; 
 
    // This is redundant, just use the other constructor 
    //   as we never touch the HRESULT in this anyway 
    CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr); 
 
    /* Return the owner of this object */ 
 
    LPUNKNOWN GetOwner() const { 
        return m_pUnknown; 
    }; 
 
    /* Called from the class factory to create a new instance, it is 
       pure virtual so it must be overriden in your derived class */ 
 
    /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ 
 
    /* Non delegating unknown implementation */ 
 
    STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); 
    STDMETHODIMP_(ULONG) NonDelegatingAddRef(); 
    STDMETHODIMP_(ULONG) NonDelegatingRelease(); 
}; 
 
/* Return an interface pointer to a requesting client 
   performing a thread safe AddRef as necessary */ 
 
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv); 
 
/* The standard InterlockedXXX functions won't take volatiles */ 
static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong ) 
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); } 
 
static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong ) 
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); } 
 
static inline LONG InterlockedExchange( volatile LONG * plong, LONG new_value ) 
{ return InterlockedExchange( const_cast<LONG*>( plong ), new_value ); } 
 
 
/* A function that can create a new COM object */ 
 
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr); 
 
/*  A function (can be NULL) which is called from the DLL entrypoint 
    routine for each factory template: 
 
    bLoading - TRUE on DLL load, FALSE on DLL unload 
    rclsid   - the m_ClsID of the entry 
*/ 
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); 
 
/* Create one of these per object class in an array so that 
   the default class factory code can create new instances */ 
 
class CFactoryTemplate { 
 
public: 
 
    const WCHAR *              m_Name; 
    const CLSID *              m_ClsID; 
    LPFNNewCOMObject           m_lpfnNew; 
    LPFNInitRoutine            m_lpfnInit; 
    const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; 
 
    BOOL IsClassID(REFCLSID rclsid) const { 
        return (IsEqualCLSID(*m_ClsID,rclsid)); 
    }; 
 
    CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const { 
        CheckPointer(phr,NULL); 
        return m_lpfnNew(pUnk, phr); 
    }; 
}; 
 
 
/* You must override the (pure virtual) NonDelegatingQueryInterface to return 
   interface pointers (using GetInterface) to the interfaces your derived 
   class supports (the default implementation only supports IUnknown) */ 
 
#define DECLARE_IUNKNOWN                                        \ 
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {      \ 
        return GetOwner()->QueryInterface(riid,ppv);            \ 
    };                                                          \ 
    STDMETHODIMP_(ULONG) AddRef() {                             \ 
        return GetOwner()->AddRef();                            \ 
    };                                                          \ 
    STDMETHODIMP_(ULONG) Release() {                            \ 
        return GetOwner()->Release();                           \ 
    }; 
 
 
 
HINSTANCELoadOLEAut32(); 
 
 
#endif /* __COMBASE__ */