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