270 lines
7.8 KiB
C++
270 lines
7.8 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: ComBase.cpp
|
|
//
|
|
// Desc: DirectShow base classes - implements class hierarchy for creating
|
|
// COM objects.
|
|
//
|
|
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include <pjmedia-videodev/config.h>
|
|
|
|
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
|
|
|
|
#include <streams.h>
|
|
#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
|
|
|
|
|
|
/* Define the static member variable */
|
|
|
|
LONG CBaseObject::m_cObjects = 0;
|
|
|
|
|
|
/* Constructor */
|
|
|
|
CBaseObject::CBaseObject(__in_opt LPCTSTR pName)
|
|
{
|
|
/* Increment the number of active objects */
|
|
InterlockedIncrement(&m_cObjects);
|
|
|
|
#ifdef DEBUG
|
|
|
|
#ifdef UNICODE
|
|
m_dwCookie = DbgRegisterObjectCreation(0, pName);
|
|
#else
|
|
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
CBaseObject::CBaseObject(const char *pName)
|
|
{
|
|
/* Increment the number of active objects */
|
|
InterlockedIncrement(&m_cObjects);
|
|
|
|
#ifdef DEBUG
|
|
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
HINSTANCE hlibOLEAut32;
|
|
|
|
/* Destructor */
|
|
|
|
CBaseObject::~CBaseObject()
|
|
{
|
|
/* Decrement the number of objects active */
|
|
if (InterlockedDecrement(&m_cObjects) == 0) {
|
|
if (hlibOLEAut32) {
|
|
FreeLibrary(hlibOLEAut32);
|
|
|
|
hlibOLEAut32 = 0;
|
|
}
|
|
};
|
|
|
|
|
|
#ifdef DEBUG
|
|
DbgRegisterObjectDestruction(m_dwCookie);
|
|
#endif
|
|
}
|
|
|
|
static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll");
|
|
|
|
HINSTANCE LoadOLEAut32()
|
|
{
|
|
if (hlibOLEAut32 == 0) {
|
|
|
|
hlibOLEAut32 = LoadLibrary(szOle32Aut);
|
|
}
|
|
|
|
return hlibOLEAut32;
|
|
}
|
|
|
|
|
|
/* Constructor */
|
|
|
|
// We know we use "this" in the initialization list, we also know we don't modify *phr.
|
|
#pragma warning( disable : 4355 4100 )
|
|
CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk)
|
|
: CBaseObject(pName)
|
|
/* Start the object with a reference count of zero - when the */
|
|
/* object is queried for it's first interface this may be */
|
|
/* incremented depending on whether or not this object is */
|
|
/* currently being aggregated upon */
|
|
, m_cRef(0)
|
|
/* Set our pointer to our IUnknown interface. */
|
|
/* If we have an outer, use its, otherwise use ours. */
|
|
/* This pointer effectivly points to the owner of */
|
|
/* this object and can be accessed by the GetOwner() method. */
|
|
, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
|
/* Why the double cast? Well, the inner cast is a type-safe cast */
|
|
/* to pointer to a type from which we inherit. The second is */
|
|
/* type-unsafe but works because INonDelegatingUnknown "behaves */
|
|
/* like" IUnknown. (Only the names on the methods change.) */
|
|
{
|
|
// Everything we need to do has been done in the initializer list
|
|
}
|
|
|
|
// This does the same as above except it has a useless HRESULT argument
|
|
// use the previous constructor, this is just left for compatibility...
|
|
CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) :
|
|
CBaseObject(pName),
|
|
m_cRef(0),
|
|
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
|
{
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk)
|
|
: CBaseObject(pName), m_cRef(0),
|
|
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
|
{ }
|
|
|
|
CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) :
|
|
CBaseObject(pName), m_cRef(0),
|
|
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
|
{ }
|
|
|
|
#endif
|
|
|
|
#pragma warning( default : 4355 4100 )
|
|
|
|
|
|
/* QueryInterface */
|
|
|
|
STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv)
|
|
{
|
|
CheckPointer(ppv,E_POINTER);
|
|
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
|
|
|
/* We know only about IUnknown */
|
|
|
|
if (riid == IID_IUnknown) {
|
|
GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
|
|
return NOERROR;
|
|
} else {
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
/* We have to ensure that we DON'T use a max macro, since these will typically */
|
|
/* lead to one of the parameters being evaluated twice. Since we are worried */
|
|
/* about concurrency, we can't afford to access the m_cRef twice since we can't */
|
|
/* afford to run the risk that its value having changed between accesses. */
|
|
|
|
template<class T> inline static T ourmax( const T & a, const T & b )
|
|
{
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
/* AddRef */
|
|
|
|
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
|
|
{
|
|
LONG lRef = InterlockedIncrement( &m_cRef );
|
|
ASSERT(lRef > 0);
|
|
DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
|
|
m_dwCookie, m_cRef));
|
|
return ourmax(ULONG(m_cRef), 1ul);
|
|
}
|
|
|
|
|
|
/* Release */
|
|
|
|
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
|
|
{
|
|
/* If the reference count drops to zero delete ourselves */
|
|
|
|
LONG lRef = InterlockedDecrement( &m_cRef );
|
|
ASSERT(lRef >= 0);
|
|
|
|
DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
|
|
m_dwCookie, m_cRef));
|
|
if (lRef == 0) {
|
|
|
|
// COM rules say we must protect against re-entrancy.
|
|
// If we are an aggregator and we hold our own interfaces
|
|
// on the aggregatee, the QI for these interfaces will
|
|
// addref ourselves. So after doing the QI we must release
|
|
// a ref count on ourselves. Then, before releasing the
|
|
// private interface, we must addref ourselves. When we do
|
|
// this from the destructor here it will result in the ref
|
|
// count going to 1 and then back to 0 causing us to
|
|
// re-enter the destructor. Hence we add an extra refcount here
|
|
// once we know we will delete the object.
|
|
// for an example aggregator see filgraph\distrib.cpp.
|
|
|
|
m_cRef++;
|
|
|
|
delete this;
|
|
return ULONG(0);
|
|
} else {
|
|
// Don't touch m_cRef again even in this leg as the object
|
|
// may have just been released on another thread too
|
|
return ourmax(ULONG(lRef), 1ul);
|
|
}
|
|
}
|
|
|
|
|
|
/* Return an interface pointer to a requesting client
|
|
performing a thread safe AddRef as necessary */
|
|
|
|
STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv)
|
|
{
|
|
CheckPointer(ppv, E_POINTER);
|
|
*ppv = pUnk;
|
|
pUnk->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/* Compares two interfaces and returns TRUE if they are on the same object */
|
|
|
|
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
|
|
{
|
|
/* Different objects can't have the same interface pointer for
|
|
any interface
|
|
*/
|
|
if (pFirst == pSecond) {
|
|
return TRUE;
|
|
}
|
|
/* OK - do it the hard way - check if they have the same
|
|
IUnknown pointers - a single object can only have one of these
|
|
*/
|
|
LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
|
|
LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
|
|
HRESULT hr; // General OLE return code
|
|
|
|
ASSERT(pFirst);
|
|
ASSERT(pSecond);
|
|
|
|
/* See if the IUnknown pointers match */
|
|
|
|
hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
|
|
if (FAILED(hr)) {
|
|
return FALSE;
|
|
}
|
|
ASSERT(pUnknown1);
|
|
|
|
/* Release the extra interface we hold */
|
|
|
|
pUnknown1->Release();
|
|
|
|
hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
|
|
if (FAILED(hr)) {
|
|
return FALSE;
|
|
}
|
|
ASSERT(pUnknown2);
|
|
|
|
/* Release the extra interface we hold */
|
|
|
|
pUnknown2->Release();
|
|
return (pUnknown1 == pUnknown2);
|
|
}
|
|
|
|
#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */
|