1
//------------------------------------------------------------------------------
4
// Desc: DirectShow base classes - defines a class hierarchy for creating
7
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8
//------------------------------------------------------------------------------
13
a. Derive your COM object from CUnknown
15
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
16
and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
17
to. The HRESULT * allows error codes to be passed around constructors and
18
the TCHAR * is a descriptive name that can be printed on the debugger.
20
It is important that constructors only change the HRESULT * if they have
21
to set an ERROR code, if it was successful then leave it alone or you may
22
overwrite an error code from an object previously created.
24
When you call a constructor the descriptive name should be in static store
25
as we do not copy the string. To stop large amounts of memory being used
26
in retail builds by all these static strings use the NAME macro,
28
CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
33
In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
34
knows not to do anything with objects that don't have a name.
36
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
37
TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
38
error, or just simply pass it through to the constructor.
40
The object creation will fail in the class factory if the HRESULT indicates
41
an error (ie FAILED(HRESULT) == TRUE)
43
d. Create a FactoryTemplate with your object's class id and CreateInstance
46
Then (for each interface) either
50
1. Also derive it from ISomeInterface
51
2. Include DECLARE_IUNKNOWN in your class definition to declare
52
implementations of QueryInterface, AddRef and Release that
53
call the outer unknown
54
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
57
if (riid == IID_ISomeInterface) {
58
return GetInterface((ISomeInterface *) this, ppv);
60
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
63
4. Declare and implement the member functions of ISomeInterface.
67
1. Declare a class derived from CUnknown
68
2. Include DECLARE_IUNKNOWN in your class definition
69
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
72
if (riid == IID_ISomeInterface) {
73
return GetInterface((ISomeInterface *) this, ppv);
75
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
78
4. Implement the member functions of ISomeInterface. Use GetOwner() to
79
access the COM object class.
81
And in your COM object class:
83
5. Make the nested class a friend of the COM object class, and declare
84
an instance of the nested class as a member of the COM object class.
86
NOTE that because you must always pass the outer unknown and an hResult
87
to the CUnknown constructor you cannot use a default constructor, in
88
other words you will have to make the member variable a pointer to the
89
class and make a NEW call in your constructor to actually create it.
91
6. override the NonDelegatingQueryInterface with code like this:
93
if (riid == IID_ISomeInterface) {
94
return m_pImplFilter->
95
NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
97
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
100
You can have mixed classes which support some interfaces via multiple
101
inheritance and some via nested classes
108
// Filter Setup data structures no defined in axextend.idl
111
AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;
113
typedef REGFILTERPINS
114
AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;
116
typedef struct _AMOVIESETUP_FILTER
119
const WCHAR * strName;
122
const AMOVIESETUP_PIN * lpPin;
124
AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
126
/* The DLLENTRY module initialises the module handle on loading */
128
extern HINSTANCE g_hInst;
130
/* On DLL load remember which platform we are running on */
132
extern DWORD g_amPlatform;
133
extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
135
/* Version of IUnknown that is renamed to allow a class to support both
136
non delegating and delegating IUnknowns in the same COM object */
138
#ifndef INONDELEGATINGUNKNOWN_DEFINED
139
DECLARE_INTERFACE(INonDelegatingUnknown)
141
STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
142
STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
143
STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
145
#define INONDELEGATINGUNKNOWN_DEFINED
148
typedef INonDelegatingUnknown *PNDUNKNOWN;
151
/* This is the base object class that supports active object counting. As
152
part of the debug facilities we trace every time a C++ object is created
153
or destroyed. The name of the object has to be passed up through the class
154
derivation list during construction as you cannot call virtual functions
155
in the constructor. The downside of all this is that every single object
156
constructor has to take an object name parameter that describes it */
163
// Disable the copy constructor and assignment by default so you will get
164
// compiler errors instead of unexpected behaviour if you pass objects
165
// by value or assign objects.
166
CBaseObject(const CBaseObject& objectSrc); // no implementation
167
void operator=(const CBaseObject& objectSrc); // no implementation
170
static LONG m_cObjects; /* Total number of objects active */
174
DWORD m_dwCookie; /* Cookie identifying this object */
180
/* These increment and decrement the number of active objects */
182
CBaseObject(__in_opt LPCTSTR pName);
184
CBaseObject(__in_opt LPCSTR pName);
188
/* Call this to find if there are any CUnknown derived objects active */
190
static LONG ObjectsActive() {
196
/* An object that supports one or more COM interfaces will be based on
197
this class. It supports counting of total objects for DLLCanUnloadNow
198
support, and an implementation of the core non delegating IUnknown */
200
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
204
const LPUNKNOWN m_pUnknown; /* Owner of this object */
206
protected: /* So we can override NonDelegatingRelease() */
207
volatile LONG m_cRef; /* Number of reference counts */
211
CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk);
212
virtual ~CUnknown() {};
214
// This is redundant, just use the other constructor
215
// as we never touch the HRESULT in this anyway
216
CUnknown(__in_opt LPCTSTR Name, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr);
218
CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk);
219
CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr);
222
/* Return the owner of this object */
224
LPUNKNOWN GetOwner() const {
228
/* Called from the class factory to create a new instance, it is
229
pure virtual so it must be overriden in your derived class */
231
/* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
233
/* Non delegating unknown implementation */
235
STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **);
236
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
237
STDMETHODIMP_(ULONG) NonDelegatingRelease();
240
/* Return an interface pointer to a requesting client
241
performing a thread safe AddRef as necessary */
243
STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv);
245
/* A function that can create a new COM object */
247
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt HRESULT *phr);
249
/* A function (can be NULL) which is called from the DLL entrypoint
250
routine for each factory template:
252
bLoading - TRUE on DLL load, FALSE on DLL unload
253
rclsid - the m_ClsID of the entry
255
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
257
/* Create one of these per object class in an array so that
258
the default class factory code can create new instances */
260
class CFactoryTemplate {
264
const WCHAR * m_Name;
265
const CLSID * m_ClsID;
266
LPFNNewCOMObject m_lpfnNew;
267
LPFNInitRoutine m_lpfnInit;
268
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;
270
BOOL IsClassID(REFCLSID rclsid) const {
271
return (IsEqualCLSID(*m_ClsID,rclsid));
274
CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) const {
275
CheckPointer(phr,NULL);
276
return m_lpfnNew(pUnk, phr);
281
/* You must override the (pure virtual) NonDelegatingQueryInterface to return
282
interface pointers (using GetInterface) to the interfaces your derived
283
class supports (the default implementation only supports IUnknown) */
285
#define DECLARE_IUNKNOWN \
286
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \
287
return GetOwner()->QueryInterface(riid,ppv); \
289
STDMETHODIMP_(ULONG) AddRef() { \
290
return GetOwner()->AddRef(); \
292
STDMETHODIMP_(ULONG) Release() { \
293
return GetOwner()->Release(); \
298
HINSTANCE LoadOLEAut32();
301
#endif /* __COMBASE__ */