/*
*********************************************************************
*
*	The Essence of OLE
*
*	Source code sample
*
*	Copyright (c) 1996, Rolling Thunder Computing, Ipswich MA
*
*	e-mail: essence@rollthunder.com
*	CompuServe: 73540,3430
*	Web: http://www.rollthunder.com
*
*	File Name: CPERTIMEDATA.CPP
*
*	Purpose: IDataObject implementation for persistent object sample
*
*********************************************************************
*/

#include <windows.h>
#include "cpertimedata.h"
#include "cenum.h"
#include "main.h"

extern UINT cfTimeData ;
extern SYSTEMTIME lt ;
extern GUID GUID_PersistTimeData ;

FORMATETC feArray []= {
						{ CF_TEXT, NULL, DVASPECT_CONTENT,  -1, TYMED_HGLOBAL },
					  };
/*
constructor/destructor 
*/

CPersistTimeData::CPersistTimeData()
{
	m_RefCount = 1 ; 
	m_bIsDirty = FALSE ;
    return;
}


CPersistTimeData::~CPersistTimeData(void)
{
	SignalObjectDestroyed( ) ;
    return;
}


HRESULT CPersistTimeData::QueryInterface(REFIID riid, LPVOID *ppv)
{
    if (riid == IID_IUnknown || riid == IID_IDataObject)
    {
        *ppv = (LPDATAOBJECT) this ;  
        AddRef();
        return S_OK ;
    }
	else if (riid == IID_IPersist || riid == IID_IPersistStream)
	{
		*ppv = (LPPERSISTSTREAM) this ;
	    AddRef();
        return S_OK ;
	}
    else
    {
    	*ppv = NULL;       
    	return  E_NOINTERFACE ;
    }
}


STDMETHODIMP_(ULONG) CPersistTimeData::AddRef(void)
{
    m_RefCount ++ ;
    return m_RefCount ;
}


STDMETHODIMP_(ULONG) CPersistTimeData::Release(void)
{
    
    m_RefCount -- ;
    
    if (m_RefCount == 0L)
    {
        delete this;
    }	return 0 ;

    return m_RefCount ;
}


/*
GetData Method.  Caller is asking if we can supply data in a given 
format and medium
*/

STDMETHODIMP CPersistTimeData::GetData (LPFORMATETC lpfe, LPSTGMEDIUM lpstg) 
{


/*
We support a private clipboard format, identified by the UINT cfTimeData.
This is actually a structure of type SYSTEMTIME. 
Allocate a new global, copy our global system time into it, and fill in the 
elements of the STGMEDIUM structure that we were passed
*/

	if (lpfe->cfFormat == cfTimeData
		&& lpfe->tymed == TYMED_HGLOBAL
		&& lpfe->dwAspect == DVASPECT_CONTENT)
	{
		SYSTEMTIME *pSt ;
			
/*
If lindex == -1, then we are simply transferring a SYSTEMTIME structure.
Any other value means that we are doing a performance test.  In this
case, the value of lindex is the amount fo memory to allocate, while
the calling app measures response time.
*/
		if (lpfe->lindex == -1)
		{
			pSt = (SYSTEMTIME *)GlobalAlloc(GMEM_FIXED, sizeof (SYSTEMTIME));
		}
		else
		{
			pSt = (SYSTEMTIME *)GlobalAlloc(GMEM_FIXED, lpfe->lindex);
		}

		if (!pSt)
		{
    		return E_OUTOFMEMORY ;
		}	                                       
		
		memmove (pSt, &lt, sizeof (SYSTEMTIME)) ;
	    
	    lpstg->tymed = TYMED_HGLOBAL ;
    	lpstg->hGlobal = (HGLOBAL) pSt ;
	   	lpstg->pUnkForRelease = NULL ; ;
    	
    	return  S_OK ;

	}


/*
User asked for a format that we couldn't supply.  Return error code.
*/
	
	return DATA_E_FORMATETC ;
}



STDMETHODIMP CPersistTimeData::QueryGetData (LPFORMATETC lpfe) 
{

/*
We'll give you our private format transferred through an HGLOBAL.
If the user is asking for this, return success code.
*/

	if (lpfe->cfFormat == cfTimeData 
		&& lpfe->tymed == TYMED_HGLOBAL
		&& lpfe->dwAspect == DVASPECT_CONTENT)
	{
		return S_OK ;
	}


/*
But we won't give you anything else
*/
	return DATA_E_FORMATETC ;
    
}

STDMETHODIMP CPersistTimeData::EnumFormatEtc (DWORD dwDir, LPENUMFORMATETC * lpEnum) 
{
	feArray [0].cfFormat = cfTimeData ;

	*lpEnum = (LPENUMFORMATETC) new CEnumerator ((LPDATAOBJECT)this, feArray, 2, 
		sizeof (FORMATETC), IID_IEnumFORMATETC) ;

	if (*lpEnum == NULL)	
	{
		return E_FAIL ;
	}
	
	return S_OK ;
}

/*
Unimplemented members
*/

STDMETHODIMP CPersistTimeData::GetDataHere (LPFORMATETC lpfe, LPSTGMEDIUM lpst)
{
	return E_NOTIMPL ;
}

STDMETHODIMP CPersistTimeData::GetCanonicalFormatEtc (LPFORMATETC lpout, LPFORMATETC lpin)
{
	return E_NOTIMPL ;
}

STDMETHODIMP CPersistTimeData::SetData (LPFORMATETC lpfe, STGMEDIUM  * lpst, BOOL fRelease)
{
	return E_NOTIMPL ;
}

STDMETHODIMP CPersistTimeData::DAdvise (FORMATETC * lpfe, DWORD dw, LPADVISESINK lpas, 
	DWORD * lpdw) 
{
	return E_NOTIMPL ;
}

STDMETHODIMP CPersistTimeData::DUnadvise  (DWORD dw)
{
	return E_NOTIMPL ;
}

STDMETHODIMP CPersistTimeData::EnumDAdvise  (LPENUMSTATDATA * lpen)
{
	*lpen = NULL ;
	return E_NOTIMPL ;
}


/*
Object has been asked for its class ID.  Return in in the output variable.
*/


STDMETHODIMP CPersistTimeData::GetClassID(CLSID * pClsID)
{
	*pClsID = GUID_PersistTimeData ;
	return S_OK ;
}

/*
Object has been asked whether it is dirty or not.  If it is, return
the success code S_OK (which has a numerical value of 0).  Otherwise,
return the error code.
*/


STDMETHODIMP CPersistTimeData::IsDirty( void)
{
	if (m_bIsDirty)
	{
		return S_OK ;
	}
	else
	{
		return S_FALSE ;
	}

}

/*
Object has been told to load itself from the supplied stream. Clear
the dirty flag and read our SYSTEMTIME structure from the place we
last put it. 
*/

STDMETHODIMP CPersistTimeData::Load(IStream *pStream)
{
	m_bIsDirty = FALSE ;
	return pStream->Read ((LPVOID) &lt, sizeof(SYSTEMTIME), NULL) ;
}


/*
Object has been told to save itself to the supplied stream.  Write our
SYSTEMTIME structure into the stream.  Clear dirty flag if told
to do so.
*/

STDMETHODIMP CPersistTimeData::Save(IStream *pStream, BOOL bClearDirty)
{
	if (bClearDirty)
	{
		m_bIsDirty = FALSE ;
	}
	return pStream->Write ((LPVOID) &lt, sizeof (SYSTEMTIME), NULL) ;
}

/*
This data object saves its size in a SYSTEMTIME structure.  That's how much
space we need.
*/

STDMETHODIMP CPersistTimeData::GetSizeMax(ULARGE_INTEGER *pLint)
{
	pLint->LowPart = sizeof (SYSTEMTIME) ;
	pLint->HighPart = 0 ;
	return S_OK ;
}
