1 //------------------------------------------------------------------------------
2 // File: ComBase.cpp
3 //
4 // Desc: DirectShow base classes - implements class hierarchy for creating
5 // COM objects.
6 //
7 // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
9
10 #include <pjmedia-videodev/config.h>
11
12 #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
13
14 #include <streams.h>
15 #pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
16
17
18 /* Define the static member variable */
19
20 LONG CBaseObject::m_cObjects = 0;
21
22
23 /* Constructor */
24
CBaseObject(__in_opt LPCTSTR pName)25 CBaseObject::CBaseObject(__in_opt LPCTSTR pName)
26 {
27 /* Increment the number of active objects */
28 InterlockedIncrement(&m_cObjects);
29
30 #ifdef DEBUG
31
32 #ifdef UNICODE
33 m_dwCookie = DbgRegisterObjectCreation(0, pName);
34 #else
35 m_dwCookie = DbgRegisterObjectCreation(pName, 0);
36 #endif
37
38 #endif
39 }
40
41 #ifdef UNICODE
CBaseObject(const char * pName)42 CBaseObject::CBaseObject(const char *pName)
43 {
44 /* Increment the number of active objects */
45 InterlockedIncrement(&m_cObjects);
46
47 #ifdef DEBUG
48 m_dwCookie = DbgRegisterObjectCreation(pName, 0);
49 #endif
50 }
51 #endif
52
53 HINSTANCE hlibOLEAut32;
54
55 /* Destructor */
56
~CBaseObject()57 CBaseObject::~CBaseObject()
58 {
59 /* Decrement the number of objects active */
60 if (InterlockedDecrement(&m_cObjects) == 0) {
61 if (hlibOLEAut32) {
62 FreeLibrary(hlibOLEAut32);
63
64 hlibOLEAut32 = 0;
65 }
66 };
67
68
69 #ifdef DEBUG
70 DbgRegisterObjectDestruction(m_dwCookie);
71 #endif
72 }
73
74 static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll");
75
LoadOLEAut32()76 HINSTANCE LoadOLEAut32()
77 {
78 if (hlibOLEAut32 == 0) {
79
80 hlibOLEAut32 = LoadLibrary(szOle32Aut);
81 }
82
83 return hlibOLEAut32;
84 }
85
86
87 /* Constructor */
88
89 // We know we use "this" in the initialization list, we also know we don't modify *phr.
90 #pragma warning( disable : 4355 4100 )
CUnknown(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN pUnk)91 CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk)
92 : CBaseObject(pName)
93 /* Start the object with a reference count of zero - when the */
94 /* object is queried for it's first interface this may be */
95 /* incremented depending on whether or not this object is */
96 /* currently being aggregated upon */
97 , m_cRef(0)
98 /* Set our pointer to our IUnknown interface. */
99 /* If we have an outer, use its, otherwise use ours. */
100 /* This pointer effectivly points to the owner of */
101 /* this object and can be accessed by the GetOwner() method. */
102 , m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
103 /* Why the double cast? Well, the inner cast is a type-safe cast */
104 /* to pointer to a type from which we inherit. The second is */
105 /* type-unsafe but works because INonDelegatingUnknown "behaves */
106 /* like" IUnknown. (Only the names on the methods change.) */
107 {
108 // Everything we need to do has been done in the initializer list
109 }
110
111 // This does the same as above except it has a useless HRESULT argument
112 // use the previous constructor, this is just left for compatibility...
CUnknown(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN pUnk,__inout_opt HRESULT * phr)113 CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) :
114 CBaseObject(pName),
115 m_cRef(0),
116 m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
117 {
118 }
119
120 #ifdef UNICODE
CUnknown(__in_opt LPCSTR pName,__in_opt LPUNKNOWN pUnk)121 CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk)
122 : CBaseObject(pName), m_cRef(0),
123 m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
124 { }
125
CUnknown(__in_opt LPCSTR pName,__in_opt LPUNKNOWN pUnk,__inout_opt HRESULT * phr)126 CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) :
127 CBaseObject(pName), m_cRef(0),
128 m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
129 { }
130
131 #endif
132
133 #pragma warning( default : 4355 4100 )
134
135
136 /* QueryInterface */
137
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)138 STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv)
139 {
140 CheckPointer(ppv,E_POINTER);
141 ValidateReadWritePtr(ppv,sizeof(PVOID));
142
143 /* We know only about IUnknown */
144
145 if (riid == IID_IUnknown) {
146 GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
147 return NOERROR;
148 } else {
149 *ppv = NULL;
150 return E_NOINTERFACE;
151 }
152 }
153
154 /* We have to ensure that we DON'T use a max macro, since these will typically */
155 /* lead to one of the parameters being evaluated twice. Since we are worried */
156 /* about concurrency, we can't afford to access the m_cRef twice since we can't */
157 /* afford to run the risk that its value having changed between accesses. */
158
ourmax(const T & a,const T & b)159 template<class T> inline static T ourmax( const T & a, const T & b )
160 {
161 return a > b ? a : b;
162 }
163
164 /* AddRef */
165
STDMETHODIMP_(ULONG)166 STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
167 {
168 LONG lRef = InterlockedIncrement( &m_cRef );
169 ASSERT(lRef > 0);
170 DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
171 m_dwCookie, m_cRef));
172 return ourmax(ULONG(m_cRef), 1ul);
173 }
174
175
176 /* Release */
177
STDMETHODIMP_(ULONG)178 STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
179 {
180 /* If the reference count drops to zero delete ourselves */
181
182 LONG lRef = InterlockedDecrement( &m_cRef );
183 ASSERT(lRef >= 0);
184
185 DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
186 m_dwCookie, m_cRef));
187 if (lRef == 0) {
188
189 // COM rules say we must protect against re-entrancy.
190 // If we are an aggregator and we hold our own interfaces
191 // on the aggregatee, the QI for these interfaces will
192 // addref ourselves. So after doing the QI we must release
193 // a ref count on ourselves. Then, before releasing the
194 // private interface, we must addref ourselves. When we do
195 // this from the destructor here it will result in the ref
196 // count going to 1 and then back to 0 causing us to
197 // re-enter the destructor. Hence we add an extra refcount here
198 // once we know we will delete the object.
199 // for an example aggregator see filgraph\distrib.cpp.
200
201 m_cRef++;
202
203 delete this;
204 return ULONG(0);
205 } else {
206 // Don't touch m_cRef again even in this leg as the object
207 // may have just been released on another thread too
208 return ourmax(ULONG(lRef), 1ul);
209 }
210 }
211
212
213 /* Return an interface pointer to a requesting client
214 performing a thread safe AddRef as necessary */
215
GetInterface(LPUNKNOWN pUnk,__out void ** ppv)216 STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv)
217 {
218 CheckPointer(ppv, E_POINTER);
219 *ppv = pUnk;
220 pUnk->AddRef();
221 return NOERROR;
222 }
223
224
225 /* Compares two interfaces and returns TRUE if they are on the same object */
226
IsEqualObject(IUnknown * pFirst,IUnknown * pSecond)227 BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
228 {
229 /* Different objects can't have the same interface pointer for
230 any interface
231 */
232 if (pFirst == pSecond) {
233 return TRUE;
234 }
235 /* OK - do it the hard way - check if they have the same
236 IUnknown pointers - a single object can only have one of these
237 */
238 LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
239 LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
240 HRESULT hr; // General OLE return code
241
242 ASSERT(pFirst);
243 ASSERT(pSecond);
244
245 /* See if the IUnknown pointers match */
246
247 hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
248 if (FAILED(hr)) {
249 return FALSE;
250 }
251 ASSERT(pUnknown1);
252
253 /* Release the extra interface we hold */
254
255 pUnknown1->Release();
256
257 hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
258 if (FAILED(hr)) {
259 return FALSE;
260 }
261 ASSERT(pUnknown2);
262
263 /* Release the extra interface we hold */
264
265 pUnknown2->Release();
266 return (pUnknown1 == pUnknown2);
267 }
268
269 #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */
270