311 lines
9.8 KiB
C
311 lines
9.8 KiB
C
|
//------------------------------------------------------------------------------
|
||
|
// File: ComBase.h
|
||
|
//
|
||
|
// Desc: DirectShow base classes - defines a class hierarchy for creating
|
||
|
// COM objects.
|
||
|
//
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
//
|
||
|
// December 1994
|
||
|
//
|
||
|
//@@END_MSINTERNAL
|
||
|
// 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(const TCHAR *pName);
|
||
|
#ifdef UNICODE
|
||
|
CBaseObject(const char *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(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);
|
||
|
#ifdef UNICODE
|
||
|
CUnknown(const char *pName, LPUNKNOWN pUnk);
|
||
|
CUnknown(char *pName, LPUNKNOWN pUnk,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, 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);
|
||
|
|
||
|
/* 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(); \
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
HINSTANCE LoadOLEAut32();
|
||
|
|
||
|
|
||
|
#endif /* __COMBASE__ */
|
||
|
|
||
|
|
||
|
|
||
|
|