//
// This file contains the implementation of SHCreateDefClassObject
//

#include "shellprv.h"
#pragma  hdrstop

typedef struct
{
    IClassFactory      cf;
    UINT               cRef;            // Reference count
    DWORD              dwFlags;         // Flags to control creation...
    LPFNCREATEINSTANCE pfnCreateInstance;          // CreateInstance callback entry
    UINT *        pcRefDll;     // Reference count of the DLL
} CClassFactory;

STDMETHODIMP CClassFactory_QueryInterface(IClassFactory *pcf, REFIID riid, void **ppvObj)
{
    CClassFactory *this = IToClass(CClassFactory, cf, pcf);
    if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
    {
        InterlockedIncrement(&this->cRef);
        *ppvObj = (LPVOID) (IClassFactory *) &this->cf;
        return NOERROR;
    }

    *ppvObj = NULL;
    return E_NOINTERFACE;
}

STDMETHODIMP_(ULONG) CClassFactory_AddRef(IClassFactory *pcf)
{
    CClassFactory *this = IToClass(CClassFactory, cf, pcf);
    return this->cRef;
}

STDMETHODIMP_(ULONG) CClassFactory_Release(IClassFactory *pcf)
{
    CClassFactory *this = IToClass(CClassFactory, cf, pcf);
    if (--this->cRef > 0)
	return this->cRef;

    LocalFree((HLOCAL)this);

    return 0;
}

STDMETHODIMP CClassFactory_CreateInstance(IClassFactory *pcf, IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
{
    CClassFactory *this = IToClass(CClassFactory, cf, pcf);

    *ppvObject = NULL;

    if (pUnkOuter)
        return CLASS_E_NOAGGREGATION;

    return this->pfnCreateInstance(pUnkOuter, riid, ppvObject);
}

STDMETHODIMP CClassFactory_LockServer(IClassFactory *pcf, BOOL fLock)
{
    CClassFactory *this = IToClass(CClassFactory, cf, pcf);
    if (this->pcRefDll)
    {
        if (fLock)
	    this->pcRefDll++;
        else
	    this->pcRefDll--;
    }
    return S_OK;
}

const IClassFactoryVtbl c_vtblAppUIClassFactory = {
    CClassFactory_QueryInterface, CClassFactory_AddRef, CClassFactory_Release,
    CClassFactory_CreateInstance,
    CClassFactory_LockServer
};

//
// creates a simple default implementation of IClassFactory
//
// Parameters:
//  riid     -- Specifies the interface to the class object
//  ppv      -- Specifies the pointer to LPVOID where the class object pointer
//               will be returned.
//  pfnCreateInstance   -- Specifies the callback entry for instanciation.
//  pcRefDll -- Specifies the address to the DLL reference count (optional)
//
// Notes:
//   The riidInst will be specified only if the instance of the class
//  support only one interface.
//
// we would like to get rid of this
// this API called by MMSYS.CPL, RNAUI.DLL, SYNCUI.DLL

STDAPI SHCreateDefClassObject(REFIID riid, void **ppv, LPFNCREATEINSTANCE pfnCreateInstance, UINT *pcRefDll, REFIID riidInst)
{
    *ppv = NULL;

    if (IsEqualIID(riid, &IID_IClassFactory))
    {
        CClassFactory *pacf = (CClassFactory *)LocalAlloc(LPTR, SIZEOF(CClassFactory));
        if (pacf)
        {
            pacf->cf.lpVtbl = &c_vtblAppUIClassFactory;
            pacf->cRef++;  // pacf->cRef=0; (generates smaller code)
            pacf->pcRefDll = pcRefDll;
            pacf->pfnCreateInstance = pfnCreateInstance;

            (IClassFactory *)*ppv = &pacf->cf;
            return NOERROR;
        }
        return E_OUTOFMEMORY;
    }
    return E_NOINTERFACE;
}
