///////////////////////////////////////////////////////////////////////////////
/*  File: factory.cpp

    Description: Contains the member function definitions for class
        DiskQuotaControlClassFactory.  The class factory object generates
        new instances of DiskQuotaControl objects.  The object implements
        IClassFactory.


    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    05/22/96    Initial creation.                                    BrianAu
    08/15/96    Added shell extension support.                       BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
#include "pch.h" // PCH
#pragma hdrstop

#include "dskquota.h"
#include "control.h"
#include "factory.h"

//
// Verify that build is UNICODE.
//
#if !defined(UNICODE)
#   error This module must be compiled UNICODE.
#endif


extern LONG g_cLockThisDll;  // Supports LockServer().


///////////////////////////////////////////////////////////////////////////////
/*  Function: DiskQuotaControlClassFactory::QueryInterface

    Description: Retrieves a pointer to the IUnknown or IClassFactory 
        interface.  Recoginizes the IID_IUnknown and IID_IClassFactory
        interface IDs.

    Arguments:
        riid - Reference to requested interface ID.

        ppvOut - Address of interface pointer variable to accept interface ptr.

    Returns:
        NOERROR        - Success.
        E_NOINTERFACE   - Requested interface not supported.
        E_INVALIDARG    - ppvOut argument was NULL.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    05/22/96    Initial creation.                                    BrianAu
    08/15/96    Added IShellPropSheetExt                             BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP 
DiskQuotaControlClassFactory::QueryInterface(
    REFIID riid, 
    LPVOID *ppvOut
    )
{
    DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControlClassFactory::QueryInterface")));
    DBGPRINTIID(DM_CONTROL, DL_MID, riid);

    HRESULT hr = E_NOINTERFACE;

    if (NULL == ppvOut)
        return E_INVALIDARG;

    *ppvOut = NULL;
    if (IID_IUnknown == riid || IID_IClassFactory == riid)
    {
        *ppvOut = this;
        ((LPUNKNOWN)*ppvOut)->AddRef();
        hr = NOERROR;
    }

    return hr;
}

///////////////////////////////////////////////////////////////////////////////
/*  Function: DiskQuotaControlClassFactory::AddRef

    Description: Increments object reference count.

    Arguments: None.

    Returns: New reference count value.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    05/22/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) 
DiskQuotaControlClassFactory::AddRef(
   VOID
   )
{
    DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControlClassFactory::AddRef")));
    DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X  %d -> %d"),
                     this, m_cRef, m_cRef + 1));

    ULONG ulReturn = m_cRef + 1;
    InterlockedIncrement(&m_cRef);
    return ulReturn;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: DiskQuotaControlClassFactory::Release

    Description: Decrements object reference count.  If count drops to 0,
        object is deleted.

    Arguments: None.

    Returns: New reference count value.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    05/22/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) 
DiskQuotaControlClassFactory::Release(
    VOID
    )
{
    DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControlClassFactory::Release")));
    DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X  %d -> %d"),
                     this, m_cRef, m_cRef - 1));

    ULONG ulReturn = m_cRef - 1;
    if (InterlockedDecrement(&m_cRef) == 0)
    {   
        delete this;
        ulReturn = 0;
    }
    return ulReturn;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: DiskQuotaControlClassFactory::CreateInstance

    Description: Creates a new instance of a DiskQuotaControl object, returning
        a pointer to its IDiskQuotaControl interface.

    Arguments:
        pUnkOuter - Pointer to outer object's IUnknown interface for IUnknown
            delegation in support of aggregation.  Aggregation is not supported
            by IDiskQuotaControl.

        riid - Reference to interface ID being requested.

        ppvOut - Address of interface pointer variable to accept interface
            pointer.

    Returns:
        NOERROR               - Success.
        E_OUTOFMEMORY         - Insufficient memory to create new object.
        E_NOINTERFACE         - Requested interface not supported.
        E_INVALIDARG          - ppvOut arg was NULL.
        CLASS_E_NOAGGREGATION - Aggregation was requested but is not supported.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    05/22/96    Initial creation.                                    BrianAu
    08/15/96    Added shell extension support.                       BrianAu
    08/20/97    Added IDispatch support.                             BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP 
DiskQuotaControlClassFactory::CreateInstance(
    LPUNKNOWN pUnkOuter, 
    REFIID riid, 
    LPVOID *ppvOut
    )
{
    DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlClassFactory::CreateInstance")));
    DBGPRINTIID(DM_CONTROL, DL_HIGH, riid);

    HRESULT hr = E_NOINTERFACE;

    if (NULL == ppvOut)
        return E_INVALIDARG;

    *ppvOut = NULL;

    try
    {
        if (NULL != pUnkOuter && IID_IUnknown != riid)
        {
            hr = CLASS_E_NOAGGREGATION;
        }
        else if (IID_IClassFactory == riid)
        {
            *ppvOut = this;
            ((LPUNKNOWN)*ppvOut)->AddRef();
            hr = NOERROR;
        }
        else if (IID_IDiskQuotaControl == riid ||
                 IID_IDispatch == riid ||
                 IID_IUnknown == riid)
        {
            hr = Create_IDiskQuotaControl(riid, ppvOut);
        }
    }
    catch(CAllocException& e)
    {
        DBGERROR((TEXT("Insufficient memory exception")));
        hr = E_OUTOFMEMORY;
    }
    return hr;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: DiskQuotaControlClassFactory::LockServer

    Description: Places/removes a lock on the DLL server.  See OLE 2
        documentation of IClassFactory for details.
        
    Arguments:
        fLock - TRUE = Increment lock count, FALSE = Decrement lock count.

    Returns:
        S_OK    - Success.
        S_FALSE - Lock count is already 0.  Can't be decremented.
        

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    05/22/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP 
DiskQuotaControlClassFactory::LockServer(
    BOOL fLock
    )
{
    DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlClassFactory::LockServer")));
    HRESULT hr = S_OK;

    if (fLock)
    {
        //
        // Increment the lock count.
        //
        InterlockedIncrement(&g_cLockThisDll);
    }
    else
    {
        //
        // Decrement only if lock count is > 0.
        // Otherwise, it's an error.
        //
        LONG lLock = g_cLockThisDll - 1;
        if (0 <= lLock)
        {
            InterlockedDecrement(&g_cLockThisDll);
        }
        else
            hr = S_FALSE;  // Lock count already at 0.
    }

    return hr;
}



///////////////////////////////////////////////////////////////////////////////
/*  Function: DiskQuotaControlClassFactory::Create_IDiskQuotaControl

    Description: Creates a DiskQuotaControl object and returns a pointer
        to it's IDiskQuotaControl interface.

    Arguments:
        ppvOut - Address of interface pointer variable to receive the interface
            pointer.

        riid - Reference to interface ID requested.

    Returns:
        NOERROR        - Success.

    Exceptions: OutOfMemory.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    08/15/96    Initial creation.                                    BrianAu
                Broke code out of CreateInstance().
    08/20/97    Added riid argument.                                 BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
DiskQuotaControlClassFactory::Create_IDiskQuotaControl(
    REFIID riid,
    LPVOID *ppvOut
    )
{
    DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControlClassFactory::Create_IDiskQuotaControl")));
    DBGASSERT((NULL != ppvOut));

    HRESULT hr = NOERROR;
    DiskQuotaControl *pController = new DiskQuotaControl;

    hr = pController->QueryInterface(riid, ppvOut);

    if (FAILED(hr))
    {
        delete pController;
    }

    return hr;
}

