blob: f735ba921a263aa9a3706f31bb3b57bd2be4b21f [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001//------------------------------------------------------------------------------
2// File: ComBase.h
3//
4// Desc: DirectShow base classes - defines a class hierarchy for creating
5// COM objects.
6//
7// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8//------------------------------------------------------------------------------
9
10
11/*
12
13a. Derive your COM object from CUnknown
14
15b. 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.
19
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.
23
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,
27
28 CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
29 if (FAILED(hr)) {
30 return hr;
31 }
32
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.
35
36c. 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.
39
40 The object creation will fail in the class factory if the HRESULT indicates
41 an error (ie FAILED(HRESULT) == TRUE)
42
43d. Create a FactoryTemplate with your object's class id and CreateInstance
44 function.
45
46Then (for each interface) either
47
48Multiple inheritance
49
501. Also derive it from ISomeInterface
512. Include DECLARE_IUNKNOWN in your class definition to declare
52 implementations of QueryInterface, AddRef and Release that
53 call the outer unknown
543. Override NonDelegatingQueryInterface to expose ISomeInterface by
55 code something like
56
57 if (riid == IID_ISomeInterface) {
58 return GetInterface((ISomeInterface *) this, ppv);
59 } else {
60 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
61 }
62
634. Declare and implement the member functions of ISomeInterface.
64
65or: Nested interfaces
66
671. Declare a class derived from CUnknown
682. Include DECLARE_IUNKNOWN in your class definition
693. Override NonDelegatingQueryInterface to expose ISomeInterface by
70 code something like
71
72 if (riid == IID_ISomeInterface) {
73 return GetInterface((ISomeInterface *) this, ppv);
74 } else {
75 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
76 }
77
784. Implement the member functions of ISomeInterface. Use GetOwner() to
79 access the COM object class.
80
81And in your COM object class:
82
835. 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.
85
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.
90
916. override the NonDelegatingQueryInterface with code like this:
92
93 if (riid == IID_ISomeInterface) {
94 return m_pImplFilter->
95 NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
96 } else {
97 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
98 }
99
100You can have mixed classes which support some interfaces via multiple
101inheritance and some via nested classes
102
103*/
104
105#ifndef __COMBASE__
106#define __COMBASE__
107
108// Filter Setup data structures no defined in axextend.idl
109
110typedef REGPINTYPES
111AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;
112
113typedef REGFILTERPINS
114AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;
115
116typedef struct _AMOVIESETUP_FILTER
117{
118 const CLSID * clsID;
119 const WCHAR * strName;
120 DWORD dwMerit;
121 UINT nPins;
122 const AMOVIESETUP_PIN * lpPin;
123}
124AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
125
126/* The DLLENTRY module initialises the module handle on loading */
127
128extern HINSTANCE g_hInst;
129
130/* On DLL load remember which platform we are running on */
131
132extern DWORD g_amPlatform;
133extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
134
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 */
137
138#ifndef INONDELEGATINGUNKNOWN_DEFINED
139DECLARE_INTERFACE(INonDelegatingUnknown)
140{
141 STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
142 STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
143 STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
144};
145#define INONDELEGATINGUNKNOWN_DEFINED
146#endif
147
148typedef INonDelegatingUnknown *PNDUNKNOWN;
149
150
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 */
157
158class CBaseObject
159{
160
161private:
162
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
168
169private:
170 static LONG m_cObjects; /* Total number of objects active */
171
172protected:
173#ifdef DEBUG
174 DWORD m_dwCookie; /* Cookie identifying this object */
175#endif
176
177
178public:
179
180 /* These increment and decrement the number of active objects */
181
182 CBaseObject(__in_opt LPCTSTR pName);
183#ifdef UNICODE
184 CBaseObject(__in_opt LPCSTR pName);
185#endif
186 ~CBaseObject();
187
188 /* Call this to find if there are any CUnknown derived objects active */
189
190 static LONG ObjectsActive() {
191 return m_cObjects;
192 };
193};
194
195
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 */
199
200class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
201 public CBaseObject
202{
203private:
204 const LPUNKNOWN m_pUnknown; /* Owner of this object */
205
206protected: /* So we can override NonDelegatingRelease() */
207 volatile LONG m_cRef; /* Number of reference counts */
208
209public:
210
211 CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk);
212 virtual ~CUnknown() {};
213
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);
217#ifdef UNICODE
218 CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk);
219 CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr);
220#endif
221
222 /* Return the owner of this object */
223
224 LPUNKNOWN GetOwner() const {
225 return m_pUnknown;
226 };
227
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 */
230
231 /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
232
233 /* Non delegating unknown implementation */
234
235 STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **);
236 STDMETHODIMP_(ULONG) NonDelegatingAddRef();
237 STDMETHODIMP_(ULONG) NonDelegatingRelease();
238};
239
240/* Return an interface pointer to a requesting client
241 performing a thread safe AddRef as necessary */
242
243STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv);
244
245/* A function that can create a new COM object */
246
247typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt HRESULT *phr);
248
249/* A function (can be NULL) which is called from the DLL entrypoint
250 routine for each factory template:
251
252 bLoading - TRUE on DLL load, FALSE on DLL unload
253 rclsid - the m_ClsID of the entry
254*/
255typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
256
257/* Create one of these per object class in an array so that
258 the default class factory code can create new instances */
259
260class CFactoryTemplate {
261
262public:
263
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;
269
270 BOOL IsClassID(REFCLSID rclsid) const {
271 return (IsEqualCLSID(*m_ClsID,rclsid));
272 };
273
274 CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) const {
275 CheckPointer(phr,NULL);
276 return m_lpfnNew(pUnk, phr);
277 };
278};
279
280
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) */
284
285#define DECLARE_IUNKNOWN \
286 STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \
287 return GetOwner()->QueryInterface(riid,ppv); \
288 }; \
289 STDMETHODIMP_(ULONG) AddRef() { \
290 return GetOwner()->AddRef(); \
291 }; \
292 STDMETHODIMP_(ULONG) Release() { \
293 return GetOwner()->Release(); \
294 };
295
296
297
298HINSTANCE LoadOLEAut32();
299
300
301#endif /* __COMBASE__ */
302
303
304
305