//+-------------------------------------------------------------------
//
//  File:       olebt.cpp
//
//  Contents:   Test DLL class code that be used multithreaded.
//
//  Classes:
//
//  Functions:
//
//  History:    03-Nov-94   Ricksa
//
//--------------------------------------------------------------------
#undef _UNICODE
#undef UNICODE
#include    <windows.h>
#include    <ole2.h>
#include    <uthread.h>


// Global count of
ULONG g_UseCount = 0;

void PrintDebugMsg(char *pszMsg, DWORD dwData)
{
    char wszBuf[256];
    wsprintf(wszBuf, "olebt.dll: %s %d\n", pszMsg, dwData);
    OutputDebugString(wszBuf);
}



//+-------------------------------------------------------------------
//
//  Class:    CBasicBndCF
//
//  Synopsis: Class Factory for CBasicBnd
//
//  Methods:  IUnknown      - QueryInterface, AddRef, Release
//            IClassFactory - CreateInstance
//
//  History:  03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
class FAR CBasicBndCF: public IClassFactory
{
public:

                        // Constructor/Destructor
                        CBasicBndCF(void);
                        ~CBasicBndCF();

                        // IUnknown
    STDMETHODIMP        QueryInterface(REFIID iid, void FAR * FAR * ppv);
    STDMETHODIMP_(ULONG) AddRef(void);
    STDMETHODIMP_(ULONG) Release(void);


                        // IClassFactory
    STDMETHODIMP        CreateInstance(
                            IUnknown FAR* pUnkOuter,
	                    REFIID iidInterface,
			    void FAR* FAR* ppv);

    STDMETHODIMP        LockServer(BOOL fLock);

private:

    ULONG		_cRefs;

    IUnknown *          _punkFm;
};



//+-------------------------------------------------------------------
//
//  Class:    CBasicBnd
//
//  Synopsis: Test class CBasicBnd
//
//  Methods:
//
//  History:  03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
class FAR CBasicBnd: public IPersist
{
public:
                        // Constructor/Destructor
                        CBasicBnd(void);
                        ~CBasicBnd();

                        // IUnknown
    STDMETHODIMP        QueryInterface(REFIID iid, void FAR * FAR * ppv);
    STDMETHODIMP_(ULONG) AddRef(void);
    STDMETHODIMP_(ULONG) Release(void);

                        // IPersist - only thing we implement because it
                        // gives us a nice way to figure who we are talking to.
    STDMETHODIMP        GetClassID(LPCLSID lpClassID);

private:

    ULONG               _cRefs;

    IUnknown *          _punkFm;
};


extern "C" BOOL WINAPI DllMain(
    HANDLE,
    DWORD,
    LPVOID)
{
    return TRUE;
}


//+-------------------------------------------------------------------
//
//  Function:   DllGetClassObject
//
//  Synopsis:   Called by client (from within BindToObject et al)
//              interface requested  should be IUnknown or IClassFactory -
//              Creates ClassFactory object and returns pointer to it
//
//  Arguments:  REFCLSID clsid    - class id
//              REFIID iid        - interface id
//              void FAR* FAR* ppv- pointer to class factory interface
//
//  Returns:    TRUE
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDAPI  DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
{
    *ppv = NULL;

    if (!IsEqualGUID(iid, IID_IUnknown)
        && !IsEqualGUID(iid, IID_IClassFactory)
        && !IsEqualGUID(iid, IID_IMarshal))
    {
	return E_NOINTERFACE;
    }

    if (IsEqualGUID(clsid, clsidBothThreadedDll))
    {
	IUnknown *punk = new CBasicBndCF();

        HRESULT hr = punk->QueryInterface(iid, ppv);

        punk->Release();

	return hr;
    }

    return E_FAIL;
}


STDAPI DllCanUnloadNow(void)
{
    return (g_UseCount == 0)
	? S_OK
	: S_FALSE;
}




//+-------------------------------------------------------------------
//
//  Member:     CBasicBndCF::CBasicBndCF()
//
//  Synopsis:   The constructor for CBAsicBnd.
//
//  Arguments:  None
//
//  History:    21-Nov-92  Ricksa  Created
//
//--------------------------------------------------------------------
CBasicBndCF::CBasicBndCF(void)
    : _cRefs(1), _punkFm(NULL)
{
    PrintDebugMsg("Creating Class Factory", (DWORD) this);
    g_UseCount++;
}



//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::~CBasicBndCF()
//
//  Synopsis:   The destructor for CBasicCF.
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
CBasicBndCF::~CBasicBndCF()
{
    PrintDebugMsg("Deleting Class Factory", (DWORD) this);
    g_UseCount--;

    if (_punkFm != NULL)
    {
        _punkFm->Release();
    }

    return;
}


//+-------------------------------------------------------------------
//
//  Method:     CBasicBndCF::QueryInterface
//
//  Synopsis:   Only IUnknown and IClassFactory supported
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CBasicBndCF::QueryInterface(REFIID iid, void **ppv)
{
    HRESULT hr = E_NOINTERFACE;
    *ppv = NULL;

    if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IClassFactory))
    {
        *ppv = this;
	AddRef();
        hr = S_OK;
    }
    else if (IsEqualGUID(iid, IID_IMarshal))
    {
        if (NULL == _punkFm)
        {
            hr = CoCreateFreeThreadedMarshaler(this, &_punkFm);
        }

        if (_punkFm != NULL)
        {
            return _punkFm->QueryInterface(iid, ppv);
        }
    }

    return hr;
}

//+-------------------------------------------------------------------
//
//  Method:     CBasicBndCF::AddRef
//
//  Synopsis:   Increment reference count
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CBasicBndCF::AddRef(void)
{
    return ++_cRefs;
}

//+-------------------------------------------------------------------
//
//  Method:     CBasicBndCF::Release
//
//  Synopsis:   Decrement reference count
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CBasicBndCF::Release(void)
{
    ULONG cRefs = --_cRefs;

    if (cRefs == 0)
    {
	delete this;
    }

    return cRefs;
}



//+-------------------------------------------------------------------
//
//  Method:     CBasicBndCF::CreateInstance
//
//  Synopsis:   This is called by Binding process to create the
//              actual class object
//
//--------------------------------------------------------------------
STDMETHODIMP CBasicBndCF::CreateInstance(
    IUnknown FAR* pUnkOuter,
    REFIID iidInterface,
    void FAR* FAR* ppv)
{
    HRESULT hresult = S_OK;

    if (pUnkOuter != NULL)
    {
        return CLASS_E_NOAGGREGATION;
    }

    CBasicBnd *pbb = new FAR CBasicBnd();

    if (pbb == NULL)
    {
	return E_OUTOFMEMORY;
    }

    hresult = pbb->QueryInterface(iidInterface, ppv);

    pbb->Release();

    return hresult;
}

//+-------------------------------------------------------------------
//
//  Method:	CBasicBndCF::LockServer
//
//  Synopsis:   Inc/Dec stay alive count
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------

STDMETHODIMP CBasicBndCF::LockServer(BOOL fLock)
{
    if (fLock)
    {
        g_UseCount++;
    }
    else
    {
        g_UseCount--;
    }

    return S_OK;
}


//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::CBasicBnd()
//
//  Synopsis:   The constructor for CBAsicBnd. I
//
//  Arguments:  None
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------

CBasicBnd::CBasicBnd(void)
    : _cRefs(1), _punkFm(NULL)
{
    PrintDebugMsg("Creating App Object", (DWORD) this);
    g_UseCount++;
}

//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::~CBasicBndObj()
//
//  Synopsis:   The destructor for CBAsicBnd.
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------

CBasicBnd::~CBasicBnd(void)
{
    PrintDebugMsg("Deleting App Object", (DWORD) this);
    g_UseCount--;
    return;
}


//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::QueryInterface
//
//  Returns:	S_OK
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CBasicBnd::QueryInterface(REFIID iid, void **ppv)
{
    if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IPersist))
    {
        *ppv = this;
	AddRef();
        return S_OK;
    }
    else if (IsEqualGUID(iid, IID_IMarshal))
    {
        HRESULT hr;

        if (NULL == _punkFm)
        {
            hr = CoCreateFreeThreadedMarshaler(this, &_punkFm);
        }

        if (_punkFm != NULL)
        {
            hr = _punkFm->QueryInterface(iid, ppv);
        }

        return hr;
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
}

//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::AddRef
//
//  Synopsis:   Standard stuff
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CBasicBnd::AddRef(void)
{
    return _cRefs++;
}

//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::Release
//
//  Synopsis:   Standard stuff
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CBasicBnd::Release(void)
{
    ULONG cRefs;

    if ((cRefs = --_cRefs) == 0)
    {
        delete this;
    }

    return cRefs;
}


//+-------------------------------------------------------------------
//
//  Member:     CBasicBnd::GetClassID
//
//  Synopsis:   Return the class id
//
//  History:    03-Nov-94  Ricksa  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CBasicBnd::GetClassID(LPCLSID classid)
{
    *classid = clsidBothThreadedDll;
    return S_OK;
}