OBJECT1.CPP

/* 
* OBJECT1.CPP
*
* Object implementation using interface implementations.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/

#include <windows.h>
#include "query.h"


//Message strings for the interface functions
static TCHAR szMessage[]=TEXT("Message from ISampleOne::GetMessage");
static TCHAR szString[] =TEXT("Message from ISampleTwo::GetString");


/*
* CreateObject1
*
* Purpose:
* Creates an instance of CObject1 returning an IUnknown
* interface.
*
* Parameters:
* ppUnk IUnknown ** in which to return the
* interface pointer.
*
* Return Value:
* BOOL TRUE if the function is successful,
* FALSE otherwise.
*/

BOOL CreateObject1(IUnknown **ppUnk)
{
HRESULT hr;
CObject1 *pObj;

if (NULL==ppUnk)
return FALSE;

//Create the new object, which gives us a C++ object pointer
pObj=new CObject1();

if (NULL==pObj)
return FALSE;

if (!pObj->Init())
return FALSE;

/*
* Now get the IUnknown interface to this object and make
* sure that it's reference count is correct. We could either
* typecast pObj to IUnknown and call AddRef explicitly, or
* we can simply call pObj->QueryInterface and let it do the
* typecast and the AddRef for us.
*/
hr=pObj->QueryInterface(IID_IUnknown, (PPVOID)ppUnk);
return SUCCEEDED(hr);
}





/*
* CObject1::CObject1
* CObject1::~CObject1
*
* Constructor Parameters:
* None
*/

CObject1::CObject1(void)
{
m_cRef=0;

m_pImpISampleOne=NULL;
m_pImpISampleTwo=NULL;

return;
}

CObject1::~CObject1(void)
{
//Delete the interface implementations created in Init
DeleteInterfaceImp(m_pImpISampleTwo);
DeleteInterfaceImp(m_pImpISampleOne);
return;
}



/*
* CObject1::Init
*
* Purpose:
* Instantiates the interface implementations for this object.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if initialization succeeds, FALSE otherwise.
*/

BOOL CObject1::Init(void)
{
/*
* Creating the interfaces means creating instances of
* the interface implementation classes. The constructor
* parameters is a pointer to CObject1 that has the
* IUnknown functions to which the interface implementations
* delegate.
*/

m_pImpISampleOne=new CImpISampleOne(this);

if (NULL==m_pImpISampleOne)
return FALSE;

m_pImpISampleTwo=new CImpISampleTwo(this);

if (NULL==m_pImpISampleTwo)
return FALSE;

return TRUE;
}






/*
* CObject1::QueryInterface
*
* Purpose:
* Manages the interfaces for this object which supports the
* IUnknown, ISampleOne, and ISampleTwo interfaces.
*
* Parameters:
* riid REFIID of the interface to return.
* ppv PPVOID in which to store the pointer.
*
* Return Value:
* HRESULT NOERROR on success, E_NOINTERFACE if the
* interface is not supported.
*/

STDMETHODIMP CObject1::QueryInterface(REFIID riid, PPVOID ppv)
{
//Always NULL the out-parameters
*ppv=NULL;

/*
* IUnknown comes from CObject1. Note that here and in
* the lines below we do not need to explicitly typecast
* the object pointers into interface pointers because
* the vtables are identical. If we had additional virtual
* member functions in the object, we would have to cast
* in order to set the right vtable. This is demonstrated
* in the multiple-inheritance version, CObject3.
*/
if (IID_IUnknown==riid)
*ppv=this;

//Other interfaces come from interface implementations
if (IID_ISampleOne==riid)
*ppv=m_pImpISampleOne;

if (IID_ISampleTwo==riid)
*ppv=m_pImpISampleTwo;

if (NULL==*ppv)
return ResultFromScode(E_NOINTERFACE);

//AddRef any interface we'll return.
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}



/*
* CObject1::AddRef
* CObject1::Release
*
* Reference counting members. When Release sees a zero count
* the object destroys itself.
*/

DWORD CObject1::AddRef(void)
{
return ++m_cRef;
}

DWORD CObject1::Release(void)
{
if (0!=--m_cRef)
return m_cRef;

delete this;
return 0;
}




//CImpISampleOne interface implementation


/*
* CImpISampleOne::CImpISampleOne
* CImpISampleOne::~CImpISampleOne
*
* Constructor Parameters:
* pObj PCObject1 to the outer object
*/

CImpISampleOne::CImpISampleOne(PCObject1 pObj)
{
m_cRef=0;
m_pObj=pObj;
return;
}

CImpISampleOne::~CImpISampleOne(void)
{
return;
}



/*
* CImpISampleOne::QueryInterface
* CImpISampleOne::AddRef
* CImpISampleOne::Release
*
* IUnknown members that delegate to m_pObj
*/

STDMETHODIMP CImpISampleOne::QueryInterface(REFIID riid, PPVOID ppv)
{
return m_pObj->QueryInterface(riid, ppv);
}

DWORD CImpISampleOne::AddRef(void)
{
/*
* We maintain an "interface reference count" for debugging
* purposes, because the client of an object should match
* AddRef and Release calls through each interface pointer.
*/
++m_cRef;
return m_pObj->AddRef();
}

DWORD CImpISampleOne::Release(void)
{
/*
* m_cRef is again only for debugging. It doesn't affect
* CObject1 although the call to m_pObj->Release does.
*/
--m_cRef;
return m_pObj->Release();
}



/*
* CImpISampleOne::GetMessage
*
* Purpose:
* Returns a string to the caller.
*
* Parameters:
* psz LPTSTR in which to store the string.
* cch UINT size of psz.
*
* Return Value:
* HRESULT NOERROR if the string is stored, E_OUTOFMEMORY
* if the buffer is too small.
*/

STDMETHODIMP CImpISampleOne::GetMessage(LPTSTR psz, UINT cch)
{
if (NULL==psz)
return ResultFromScode(E_POINTER);

if (cch < (UINT)lstrlen(szMessage))
return ResultFromScode(E_OUTOFMEMORY);

lstrcpy(psz, szMessage);
return NOERROR;
}







//CImpISampleTwo interface implementation


/*
* CImpISampleTwo::CImpISampleTwo
* CImpISampleTwo::~CImpISampleTwo
*
* Constructor Parameters:
* pObj PCObject1 to the outer object
*/

CImpISampleTwo::CImpISampleTwo(PCObject1 pObj)
{
m_cRef=0;
m_pObj=pObj;
return;
}

CImpISampleTwo::~CImpISampleTwo(void)
{
return;
}



/*
* CImpISampleTwo::QueryInterface
* CImpISampleTwo::AddRef
* CImpISampleTwo::Release
*
* IUnknown members that delegate to m_pObj
*/

STDMETHODIMP CImpISampleTwo::QueryInterface(REFIID riid, PPVOID ppv)
{
return m_pObj->QueryInterface(riid, ppv);
}

DWORD CImpISampleTwo::AddRef(void)
{
/*
* We maintain an "interface reference count" for debugging
* purposes, because the client of an object should match
* AddRef and Release calls through each interface pointer.
*/
++m_cRef;
return m_pObj->AddRef();
}

DWORD CImpISampleTwo::Release(void)
{
/*
* m_cRef is again only for debugging. It doesn't affect
* CObject1 although the call to m_pObj->Release does.
*/
--m_cRef;
return m_pObj->Release();
}



/*
* CImpISampleTwo::GetString
*
* Purpose:
* Returns a string to the caller.
*
* Parameters:
* psz LPTSTR in which to store the string.
* cch UINT size of psz.
*
* Return Value:
* HRESULT NOERROR if the string is stored, E_OUTOFMEMORY
* if the buffer is too small.
*/

STDMETHODIMP CImpISampleTwo::GetString(LPTSTR psz, UINT cch)
{
if (NULL==psz)
return ResultFromScode(E_POINTER);

if (cch < (UINT)lstrlen(szString))
return ResultFromScode(E_OUTOFMEMORY);

lstrcpy(psz, szString);
return NOERROR;
}