306 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			306 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | //------------------------------------------------------------------------------
 | ||
|  | // File: ComBase.h
 | ||
|  | //
 | ||
|  | // Desc: DirectShow base classes - defines a class hierarchy for creating
 | ||
|  | //       COM objects.
 | ||
|  | //
 | ||
|  | // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 | ||
|  | //------------------------------------------------------------------------------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /*
 | ||
|  | 
 | ||
|  | 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(__in_opt LPCTSTR pName); | ||
|  | #ifdef UNICODE
 | ||
|  |     CBaseObject(__in_opt LPCSTR pName); | ||
|  | #endif
 | ||
|  |     ~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(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk); | ||
|  |     virtual ~CUnknown() {}; | ||
|  | 
 | ||
|  |     // This is redundant, just use the other constructor
 | ||
|  |     //   as we never touch the HRESULT in this anyway
 | ||
|  |     CUnknown(__in_opt LPCTSTR Name, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr); | ||
|  | #ifdef UNICODE
 | ||
|  |     CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk); | ||
|  |     CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr); | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     /* 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, __deref_out 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, __out void **ppv); | ||
|  | 
 | ||
|  | /* A function that can create a new COM object */ | ||
|  | 
 | ||
|  | typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt 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(__inout_opt LPUNKNOWN pUnk, __inout_opt 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, __deref_out void **ppv) {      \ | ||
|  |         return GetOwner()->QueryInterface(riid,ppv);            \ | ||
|  |     };                                                          \ | ||
|  |     STDMETHODIMP_(ULONG) AddRef() {                             \ | ||
|  |         return GetOwner()->AddRef();                            \ | ||
|  |     };                                                          \ | ||
|  |     STDMETHODIMP_(ULONG) Release() {                            \ | ||
|  |         return GetOwner()->Release();                           \ | ||
|  |     }; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | HINSTANCE	LoadOLEAut32(); | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif /* __COMBASE__ */
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |