// ClassFactory.h - Copyright (C) 2000 Pat Thoyts <pat@zsplat.freeserve.co.uk>
//
// Template class for COM ClassFactory objects.
//
// @(#)$Id: ClassFactory.h,v 1.1.1.1 2000/11/20 02:10:46 pat Exp $

#ifndef _H_CLASSFACTORY
#define _H_CLASSFACTORY

#if _MSC_VER > 1000
#pragma once
#endif

#include <windows.h>
#include <ole2.h>

#ifdef _MSC_VER
#pragma warning(disable:4800) // disable BOOL to bool warnings
#endif // _MSC_VER

template <typename T>
class CClassFactory : public IClassFactory
{
 public:
    STDMETHOD(QueryInterface)(REFIID riid, void** ppv);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();
    STDMETHOD(CreateInstance)(IUnknown* pUnknownOuter, REFIID riid, void** ppv);
    STDMETHOD(LockServer)(BOOL fLock);

    bool CanUnloadNow();
    void DecrementObjectCount();

 private:
    long m_lRefCount;
    long m_lObjectCount;
    long m_lLockCount;
};

// Implementation -------------------------------------------------------

template <typename T>
STDMETHODIMP CClassFactory<T>::QueryInterface(REFIID riid, void** ppv)
{
    HRESULT hr = S_OK;
    *ppv = 0;
  
    if (riid == IID_IUnknown || riid == IID_IClassFactory)
	*ppv = static_cast<IClassFactory*>(this);
    else
	hr = E_NOINTERFACE;
  
    static_cast<IUnknown*>(*ppv)->AddRef();
    return hr;
}

template <typename T>
STDMETHODIMP_(ULONG) CClassFactory<T>::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

template <typename T>
STDMETHODIMP_(ULONG) CClassFactory<T>::Release()
{
    if (InterlockedDecrement(&m_lRefCount) == 0)
    {
	// We don't delete this object, CanUnloadNow will indicate
	// that the library can be unloaded which will handle that.
	return 0;
    }
    return m_lRefCount;
}

template <typename T>
STDMETHODIMP CClassFactory<T>::CreateInstance(IUnknown * pUnknownOuter,
					      REFIID riid,
					      void** ppv)
{
    *ppv = 0;
    if (pUnknownOuter != 0) // don't aggregate
	return CLASS_E_NOAGGREGATION;
    
    T* pCoClass = new T;
    
    if (pCoClass == 0)
	return E_OUTOFMEMORY;
    
    HRESULT hr = pCoClass->QueryInterface(riid, ppv);
    if (FAILED(hr))
    {
	delete pCoClass;
	return hr;
    }
    
    InterlockedIncrement(&m_lObjectCount);
    
    return S_OK;
}

template <typename T>
STDMETHODIMP CClassFactory<T>::LockServer(BOOL fLock)
{
    if (fLock)
	InterlockedIncrement(&m_lLockCount);
    else
	InterlockedDecrement(&m_lLockCount);
    return S_OK;
}

template <typename T>
bool CClassFactory<T>::CanUnloadNow()
{
    if (m_lLockCount != 0)
	return false;
    if (m_lObjectCount != 0)
	return false;
    if (m_lRefCount != 0)
	return false;
    return true;
}

template <typename T>
void CClassFactory<T>::DecrementObjectCount()
{
    if (m_lObjectCount > 0)
	InterlockedDecrement(&m_lObjectCount);
}

#endif /* _H_CLASSFACTORY */

// Local variables:
//   mode: c++
//   indent-tabs-mode: nil
//   c-file-style: "stroustrup"
// End:

