Implementing the IltmmObjectWrapper In a Custom Object

Sometimes it is convenient to wrap an existing DirectShow filter within a custom object. This allows the user to expose a custom Interface for manipulating the filter. This is especially useful if you would like to create an automation object that wraps an existing DirectShow filter. Only automation Interfaces are accessible from languages, such as VB, and are not usually available in DirectShow filters. The only problem is, if you wrap a filter in a custom object, LEAD objects can get the underlying IBaseFIlter Interface using the IltmmObjectWrapper Interface.

When you add a source or target object to any LEAD object, and your object does not implement the IBaseFIlter Interface, the LEAD object will attempt to gain access to the underlying object through the IltmmObjectWrapper::GetWrappedObject method. The underlying object must implement the IBaseFilter Interface. The IltmmObjectWrapper::SetWrappedObject method is not used by the LEAD objects and may return E_NOTIMPL. However, the user can implement this method for convenience.

The following code shows a simple implementation of an object supporting the IltmmObjectWrapper Interface:

 

// CCustomObject - simple DirectShow filter wrapper
// Instances of this class can be passed to any LEAD object that accepts source or target objects
class CCustomObject : public IltmmObjectWrapper
{
public: 
   CCustomObject();
   virtual ~CCustomObject();

   // IUnknown

   virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); 
   virtual ULONG STDMETHODCALLTYPE AddRef(void); 
   virtual ULONG STDMETHODCALLTYPE Release(void); 

   // IltmmObjectWrapper
   virtual HRESULT STDMETHODCALLTYPE GetWrappedObject(IUnknown **ppObject); 
   virtual HRESULT STDMETHODCALLTYPE SetWrappedObject(IUnknown *pObject); 

protected: 
   ULONG m_ref; 
   IBaseFilter* m_pFilter; 
};

CCustomObject::CCustomObject() : m_pFilter(NULL), m_ref(1) 
{
}

CCustomObject::~CCustomObject()
{
   if(m_pFilter) 
      m_pFilter->Release();
}

HRESULT STDMETHODCALLTYPE CCustomObject::QueryInterface( REFIID riid,  void **ppvObject) 
{
   // object only supports IltmmObjectWrapper
   if(riid == IID_IUnknown || riid == IID_IltmmObjectWrapper) 
   {
      AddRef();
      *ppvObject = (void*) (IltmmObjectWrapper*) this; 
      return S_OK; 
   }
   return E_NOINTERFACE; 
}

ULONG STDMETHODCALLTYPE CCustomObject::AddRef( void) 
{
   return ++m_ref; 
}

ULONG STDMETHODCALLTYPE CCustomObject::Release( void) 
{
   ULONG ref = --m_ref; 
   if(!ref) 
      delete this; 
   return ref; 
}

HRESULT STDMETHODCALLTYPE CCustomObject::GetWrappedObject(IUnknown * * ppObject) 
{
   // return the wrapped filter
   if (ppObject == NULL) 
      return E_POINTER; 
   if(!m_pFilter) 
      return E_NOINTERFACE; 
   return m_pFilter->QueryInterface(IID_IUnknown, (void**) ppObject); 
}

HRESULT STDMETHODCALLTYPE CCustomObject::SetWrappedObject(IUnknown * pObject) 
{
   // wrap the filter
   IBaseFilter* pFilter = NULL; 
   if(pObject) 
   {
      HRESULT hr = pObject->QueryInterface(IID_IBaseFilter, (void**) &pFilter); 
      if(FAILED(hr)) 
         return hr; 
   }
   if(m_pFilter) 
      m_pFilter->Release();
   m_pFilter = pFilter; 
   return S_OK; 
}