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