// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFXCTL_CORE3_SEG
#pragma code_seg(AFXCTL_CORE3_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// OCX Support

////////////////////////////////////////////////////////////////////////////
// _AfxRegisterClipFormat - Registers a custom clipboard format, using the
//  string form of a class ID.

CLIPFORMAT AFXAPI _AfxRegisterClipFormat(REFCLSID clsid)
{
	TCHAR pszClsid[40];
	wsprintf(pszClsid,
		_T("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
		clsid.Data1, clsid.Data2, clsid.Data3,
		clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3],
		clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]);
	return (CLIPFORMAT)RegisterClipboardFormat(pszClsid);
}

CLIPFORMAT AFXAPI _AfxGetClipboardFormatConvertVBX()
{
	static CLIPFORMAT _cfConvertVBX;
	if (_cfConvertVBX == 0)
		_cfConvertVBX = _AfxRegisterClipFormat(CLSID_ConvertVBX);
	ASSERT(_cfConvertVBX != NULL);
	return _cfConvertVBX;
}

CLIPFORMAT AFXAPI _AfxGetClipboardFormatPersistPropset()
{
	static CLIPFORMAT _cfPersistPropset;
	if (_cfPersistPropset == 0)
		_cfPersistPropset = _AfxRegisterClipFormat(CLSID_PersistPropset);
	ASSERT(_cfPersistPropset != NULL);
	return _cfPersistPropset;
}

/////////////////////////////////////////////////////////////////////////////
// AfxOleMatchPropsetClipFormat

BOOL AFXAPI _AfxOleMatchPropsetClipFormat(CLIPFORMAT cfFormat, LPCLSID lpFmtID)
{
	if (cfFormat == _AfxGetClipboardFormatPersistPropset())
	{
		*lpFmtID = CLSID_PersistPropset;
		return TRUE;
	}

	if (cfFormat == _AfxGetClipboardFormatConvertVBX())
	{
		*lpFmtID = CLSID_ConvertVBX;
		return TRUE;
	}

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::XDataObject

STDMETHODIMP_(ULONG) COleControl::XDataObject::AddRef()
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)
	return (ULONG)pThis->ExternalAddRef();
}

STDMETHODIMP_(ULONG) COleControl::XDataObject::Release()
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)
	return (ULONG)pThis->ExternalRelease();
}

STDMETHODIMP COleControl::XDataObject::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)
	return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP COleControl::XDataObject::GetData(LPFORMATETC pformatetcIn,
	LPSTGMEDIUM pmedium )
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	CControlDataSource* pDataSource = pThis->GetDataSource();
	if (pDataSource == NULL)
		return E_OUTOFMEMORY;

	return pDataSource->m_xDataObject.GetData(pformatetcIn, pmedium);
}

STDMETHODIMP COleControl::XDataObject::GetDataHere(LPFORMATETC pformatetc,
	LPSTGMEDIUM pmedium )
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	CControlDataSource* pDataSource = pThis->GetDataSource();
	if (pDataSource == NULL)
		return E_OUTOFMEMORY;

	return pDataSource->m_xDataObject.GetDataHere(pformatetc, pmedium);
}

STDMETHODIMP COleControl::XDataObject::QueryGetData(LPFORMATETC pformatetc )
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	CControlDataSource* pDataSource = pThis->GetDataSource();
	if (pDataSource == NULL)
		return E_OUTOFMEMORY;

	return pDataSource->m_xDataObject.QueryGetData(pformatetc);
}

STDMETHODIMP COleControl::XDataObject::GetCanonicalFormatEtc(
	LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	CControlDataSource* pDataSource = pThis->GetDataSource();
	if (pDataSource == NULL)
		return E_OUTOFMEMORY;

	return pDataSource->m_xDataObject.GetCanonicalFormatEtc(pformatetc,
		pformatetcOut);
}

STDMETHODIMP COleControl::XDataObject::SetData(LPFORMATETC pformatetc,
	STGMEDIUM * pmedium, BOOL fRelease)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	CControlDataSource* pDataSource = pThis->GetDataSource();
	if (pDataSource == NULL)
		return E_OUTOFMEMORY;

	return pDataSource->m_xDataObject.SetData(pformatetc, pmedium, fRelease);
}

STDMETHODIMP COleControl::XDataObject::EnumFormatEtc(DWORD dwDirection,
	LPENUMFORMATETC* ppenumFormatEtc)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	CControlDataSource* pDataSource = pThis->GetDataSource();
	if (pDataSource == NULL)
		return E_OUTOFMEMORY;

	return pDataSource->m_xDataObject.EnumFormatEtc(dwDirection,
		ppenumFormatEtc);
}

STDMETHODIMP COleControl::XDataObject::DAdvise(FORMATETC* pFormatetc,
	DWORD advf, LPADVISESINK pAdvSink, DWORD* pdwConnection)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	*pdwConnection = 0;

	if (pThis->m_pDataAdviseHolder == NULL &&
		CreateDataAdviseHolder(&pThis->m_pDataAdviseHolder) != S_OK)
	{
		return E_OUTOFMEMORY;
	}
	ASSERT(pThis->m_pDataAdviseHolder != NULL);
	return pThis->m_pDataAdviseHolder->Advise(this, pFormatetc, advf, pAdvSink,
		pdwConnection);
}

STDMETHODIMP COleControl::XDataObject::DUnadvise(DWORD dwConnection)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	if (pThis->m_pDataAdviseHolder == NULL)
		return E_FAIL;

	ASSERT(pThis->m_pDataAdviseHolder != NULL);
	return pThis->m_pDataAdviseHolder->Unadvise(dwConnection);
}

STDMETHODIMP COleControl::XDataObject::EnumDAdvise(
	LPENUMSTATDATA* ppenumAdvise)
{
	METHOD_PROLOGUE_EX_(COleControl, DataObject)

	*ppenumAdvise = NULL;

	if (pThis->m_pDataAdviseHolder == NULL)
		return E_FAIL;

	ASSERT(pThis->m_pDataAdviseHolder != NULL);
	return pThis->m_pDataAdviseHolder->EnumAdvise(ppenumAdvise);
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::CControlDataSource

COleControl::CControlDataSource::CControlDataSource(COleControl* pCtrl) :
	m_pCtrl(pCtrl)
{
	m_nGrowBy = 4;  // By default, control puts 4 entries in cache.
}

BOOL COleControl::CControlDataSource::OnRenderGlobalData(
	LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal)
{
	ASSERT_VALID(this);
	return m_pCtrl->OnRenderGlobalData(lpFormatEtc, phGlobal);
	// Note: COleDataSource has no implementation
}

BOOL COleControl::CControlDataSource::OnRenderFileData(
	LPFORMATETC lpFormatEtc, CFile* pFile)
{
	ASSERT_VALID(this);
	return m_pCtrl->OnRenderFileData(lpFormatEtc, pFile);
	// Note: COleDataSource has no implementation
}

BOOL COleControl::CControlDataSource::OnRenderData(
	LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
	ASSERT_VALID(this);
	if (m_pCtrl->OnRenderData(lpFormatEtc, lpStgMedium))
		return TRUE;

	return COleDataSource::OnRenderData(lpFormatEtc, lpStgMedium);
}

BOOL COleControl::CControlDataSource::OnSetData(LPFORMATETC lpFormatEtc,
	LPSTGMEDIUM lpStgMedium, BOOL bRelease)
{
	ASSERT_VALID(this);
	return m_pCtrl->OnSetData(lpFormatEtc, lpStgMedium, bRelease);
	// Note: COleDataSource has no implementation
}

/////////////////////////////////////////////////////////////////////////////
// COleControl overridables for IDataObject implementation

BOOL COleControl::OnRenderGlobalData(LPFORMATETC lpFormatEtc,
	HGLOBAL* phGlobal)
{
#ifndef _DEBUG
	UNUSED(lpFormatEtc); // unused in release builds
	UNUSED(phGlobal);    // unused in release builds
#endif

	ASSERT_VALID(this);
	ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
	ASSERT(AfxIsValidAddress(phGlobal, sizeof(HGLOBAL)));

	return FALSE;   // default does nothing
}

BOOL COleControl::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
{
#ifndef _DEBUG
	UNUSED(lpFormatEtc); // unused in release builds
	UNUSED(pFile);       // unused in release builds
#endif

	ASSERT_VALID(this);
	ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC)));
	ASSERT_VALID(pFile);

	return FALSE;   // default does nothing
}

BOOL COleControl::OnRenderData(
	LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
	ASSERT_VALID(this);
	ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
	ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));

	// default implementation does not support extended layout
	if (lpFormatEtc->lindex != -1)
		return FALSE;

	// default implementation supports CF_METAFILEPICT
	if (lpFormatEtc->cfFormat == CF_METAFILEPICT)
		return GetMetafileData(lpFormatEtc, lpStgMedium);

	// default implementation supports propset format
	CLSID fmtid;
	if (_AfxOleMatchPropsetClipFormat(lpFormatEtc->cfFormat, &fmtid))
	{
		return GetPropsetData(lpFormatEtc, lpStgMedium, fmtid);
	}

	return FALSE;   // cfFormat not supported
}

BOOL COleControl::OnSetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium,
	BOOL bRelease)
{
	ASSERT_VALID(this);
	ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
	ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));

	// default implementation supports propset format
	BOOL bSuccess = FALSE;
	CLSID fmtid;
	if (_AfxOleMatchPropsetClipFormat(lpFormatEtc->cfFormat, &fmtid))
	{
		bSuccess = SetPropsetData(lpFormatEtc, lpStgMedium, fmtid);

		if (bSuccess && bRelease)
			ReleaseStgMedium(lpStgMedium);
	}

	return bSuccess;
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::GetDataSource

COleControl::CControlDataSource* COleControl::GetDataSource()
{
	TRY
	{
		if (m_pDataSource == NULL)
		{
			AFX_MANAGE_STATE(m_pModuleState);
			m_pDataSource = new CControlDataSource(this);
			ASSERT(m_pDataSource != NULL);
			SetInitialDataFormats();
		}
	}
	END_TRY

	return m_pDataSource;
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::SetInitialDataFormats

void COleControl::SetInitialDataFormats()
{
	// by default a COleControl supports CF_METAFILEPICT
	FORMATETC formatEtc;
	formatEtc.cfFormat = CF_METAFILEPICT;
	formatEtc.ptd = NULL;
	formatEtc.dwAspect = DVASPECT_CONTENT;
	formatEtc.lindex = -1;
	formatEtc.tymed = TYMED_MFPICT;
	m_pDataSource->DelayRenderData(0, &formatEtc);

	// by default a COleControl supports persistent propset format
	// (GetData or SetData)
	formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset();
	formatEtc.ptd = NULL;
	formatEtc.dwAspect = DVASPECT_CONTENT;
	formatEtc.lindex = -1;
	formatEtc.tymed = TYMED_ISTREAM | TYMED_ISTORAGE;
	m_pDataSource->DelayRenderData(0, &formatEtc);
	m_pDataSource->DelaySetData(0, &formatEtc);

	// by default a COleControl supports VBX conversion propset format
	// (SetData only)
	formatEtc.cfFormat = _AfxGetClipboardFormatConvertVBX();
	m_pDataSource->DelaySetData(0, &formatEtc);
}


/////////////////////////////////////////////////////////////////////////////
// Force any extra compiler-generated code into AFX_INIT_SEG

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
