| //------------------------------------------------------------------------------ | |
| // 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__ */ | |