// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 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_PROP_SEG
#pragma code_seg(AFXCTL_PROP_SEG)
#endif

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

#define new DEBUG_NEW

#ifdef _DEBUG
#define ASSERT_BUFFER_VALID(p, cb, bWrite) \
	ASSERT(AfxIsValidAddress(p, cb, bWrite))
#else
#define ASSERT_BUFFER_VALID(p, cb, bWrite)
#endif

// Old class ID for picture type
static const CLSID CLSID_StdPicture_V1 =
	{ 0xfb8f0824,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } };

/////////////////////////////////////////////////////////////////////////////
// _AfxGetArchiveStream

LPSTREAM AFXAPI _AfxGetArchiveStream(CArchive& ar, CArchiveStream& stm)
{
	// Obtain direct access to the archive's LPSTREAM.
	ar.Flush();
	CFile* pFile = ar.GetFile();
	ASSERT(pFile != NULL);
	LPSTREAM pstm;
	if (pFile->IsKindOf(RUNTIME_CLASS(COleStreamFile)))
	{
		pstm = ((COleStreamFile*)pFile)->m_lpStream;
		ASSERT(pstm != NULL);
	}
	else
	{
		ASSERT(stm.m_pArchive == NULL || stm.m_pArchive == &ar);
		stm.m_pArchive = &ar;
		pstm = &stm;
	}
	return pstm;
}

/////////////////////////////////////////////////////////////////////////////
// _AfxInitBlob

BOOL AFXAPI _AfxInitBlob(HGLOBAL* phDst, void* pvSrc)
{
	BOOL bResult = FALSE;
	ULONG cb;
	if ((cb = *(long*)pvSrc) > 0)
	{
		ASSERT_BUFFER_VALID(pvSrc, sizeof(cb) + cb, TRUE);
		*phDst = GlobalAlloc(GMEM_MOVEABLE, sizeof(cb) + cb);
		if (*phDst != NULL)
		{
			void* pvDst = GlobalLock(*phDst);
			ASSERT(pvDst != NULL);
			memcpy(pvDst, pvSrc, sizeof(cb) + cb);
			bResult = TRUE;
			GlobalUnlock(*phDst);
		}
	}
	return bResult;
}

/////////////////////////////////////////////////////////////////////////////
// _AfxCopyBlob

BOOL AFXAPI _AfxCopyBlob(HGLOBAL* phDst, HGLOBAL hSrc)
{
	BOOL bResult = FALSE;
	void* pvSrc = GlobalLock(hSrc);
	if (pvSrc != NULL)
	{
		bResult = _AfxInitBlob(phDst, pvSrc);
		GlobalUnlock(hSrc);
	}
	return bResult;
}

/////////////////////////////////////////////////////////////////////////////
// _AfxCopyPropValue

BOOL AFXAPI _AfxCopyPropValue(VARTYPE vtProp, void* pvDest, const void * pvSrc)
{
	ASSERT(AfxIsValidAddress(pvDest, 1));

	if (pvSrc != NULL)
	{
		ASSERT(AfxIsValidAddress(pvSrc, 1, FALSE));

		switch (vtProp)
		{
		case VT_I2:
			*(short*)pvDest = *(short*)pvSrc;
			break;
		case VT_I4:
			*(long*)pvDest = *(long*)pvSrc;
			break;
		case VT_BOOL:
			*(BOOL*)pvDest = *(BOOL*)pvSrc;
			break;
		case VT_BSTR:
			*(CString*)pvDest = *(CString*)pvSrc;
			break;
		case VT_LPSTR:
			*(CString*)pvDest = (LPCTSTR)pvSrc;
			break;
		case VT_CY:
			*(CY*)pvDest = *(CY*)pvSrc;
			break;
		case VT_R4:
			*(_AFX_FLOAT*)pvDest = *(_AFX_FLOAT*)pvSrc;
			break;
		case VT_R8:
			*(_AFX_DOUBLE*)pvDest = *(_AFX_DOUBLE*)pvSrc;
			break;
		default:
			return FALSE;
		}
	}
	return pvSrc != NULL;
}

/////////////////////////////////////////////////////////////////////////////
// COleControl::ExchangeExtent

BOOL COleControl::ExchangeExtent(CPropExchange* pPX)
{
	// Save extent
	SIZEL szl;
	szl.cx = m_cxExtent;
	szl.cy = m_cyExtent;

	if (PX_Long(pPX, _T("_ExtentX"), szl.cx) &&
		PX_Long(pPX, _T("_ExtentY"), szl.cy))
	{
		if ((pPX->IsLoading()) &&
			((m_cxExtent != szl.cx) || (m_cyExtent != szl.cy)))
		{
			m_xOleObject.SetExtent(DVASPECT_CONTENT, &szl);
		}
		return TRUE;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// Serialization for version number

DWORD COleControl::SerializeVersion(CArchive& ar, DWORD dwVersionDefault,
	BOOL bConvert)
{
	DWORD dwVersion;

	if (ar.IsLoading())
	{
		ar >> m_dwVersionLoaded;
		dwVersion = m_dwVersionLoaded;
	}
	else
	{
		dwVersion = bConvert ? dwVersionDefault : m_dwVersionLoaded;
		ar << dwVersion;
	}

	return dwVersion;
}

/////////////////////////////////////////////////////////////////////////////
// Initialization for version number

void COleControl::ResetVersion(DWORD dwVersionDefault)
{
	m_dwVersionLoaded = dwVersionDefault;
}

/////////////////////////////////////////////////////////////////////////////
// Serialization for extent

void COleControl::SerializeExtent(CArchive& ar)
{
	if (ar.IsLoading())
	{
		SIZEL szl;
		ar >> szl.cx;
		ar >> szl.cy;
		if ((m_cxExtent != szl.cx) || (m_cyExtent != szl.cy))
			m_xOleObject.SetExtent(DVASPECT_CONTENT, &szl);
	}
	else
	{
		ar << m_cxExtent;
		ar << m_cyExtent;
	}
}

/////////////////////////////////////////////////////////////////////////////
// CPropExchange member functions

BOOL CPropExchange::ExchangeVersion(DWORD& dwVersionLoaded,
	DWORD dwVersionDefault, BOOL bConvert)
{
	BOOL bResult;
	if (m_bLoading)
	{
		bResult = PX_ULong(this, _T("_Version"), m_dwVersion,
			dwVersionDefault);
		dwVersionLoaded = m_dwVersion;
	}
	else
	{
		m_dwVersion = bConvert ? dwVersionDefault : dwVersionLoaded;
		bResult = PX_ULong(this, _T("_Version"), m_dwVersion);
	}
	return bResult;
}

/////////////////////////////////////////////////////////////////////////////
// CArchivePropExchange member functions

CArchivePropExchange::CArchivePropExchange(CArchive& ar) :
	m_ar(ar)
{
	ASSERT_POINTER(&ar, CArchive);
	m_bLoading = m_ar.IsLoading();
}

BOOL CArchivePropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
		void* pvProp, const void* pvDefault)
{
	UNUSED(pszPropName);     // unused in release builds
	UNUSED(pvDefault);       // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT(AfxIsValidAddress(pvProp, 1, FALSE));
	ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE));

	if (m_bLoading)
	{
		switch (vtProp)
		{
		case VT_I2:
			m_ar >> *(WORD*)pvProp;
			break;
		case VT_I4:
			m_ar >> *(long*)pvProp;
			break;
		case VT_BOOL:
			*(BOOL*)pvProp = 0;
			m_ar >> *(BYTE*)pvProp;
			break;
		case VT_LPSTR:
		case VT_BSTR:
			m_ar >> *(CString*)pvProp;
			break;
		case VT_CY:
			m_ar >> ((CY*)pvProp)->Lo;
			m_ar >> ((CY*)pvProp)->Hi;
			break;
		case VT_R4:
			m_ar >> *(float*)pvProp;
			break;
		case VT_R8:
			m_ar >> *(double*)pvProp;
			break;
		}
	}
	else
	{
		switch (vtProp)
		{
		case VT_I2:
			m_ar << *(WORD*)pvProp;
			break;
		case VT_I4:
			m_ar << *(long*)pvProp;
			break;
		case VT_BOOL:
			m_ar << *(BYTE*)pvProp;
			break;
		case VT_LPSTR:
		case VT_BSTR:
			m_ar << *(CString*)pvProp;
			break;
		case VT_CY:
			m_ar << ((CY*)pvProp)->Lo;
			m_ar << ((CY*)pvProp)->Hi;
			break;
		case VT_R4:
			m_ar << *(float*)pvProp;
			break;
		case VT_R8:
			m_ar << *(double*)pvProp;
			break;
		}
	}

	return TRUE;
}

BOOL CArchivePropExchange::ExchangeBlobProp(LPCTSTR pszPropName,
	HGLOBAL* phBlob, HGLOBAL /*hBlobDefault*/)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(phBlob, HGLOBAL);

	DWORD cb;

	if (m_bLoading)
	{
		// free previous memory block
		if (*phBlob != NULL)
		{
			GlobalFree(*phBlob);
			*phBlob = NULL;
		}

		// read new size
		m_ar >> cb;

		// allocate and fill new memory block
		*phBlob = GlobalAlloc(GMEM_MOVEABLE, sizeof(cb)+cb);
		if (*phBlob != NULL)
		{
			void* pvBlob = GlobalLock(*phBlob);
			ASSERT(pvBlob != NULL);
			*(long*)pvBlob = cb;
			if (m_ar.Read((BYTE*)pvBlob+sizeof(cb), cb) != cb)
				AfxThrowArchiveException(CArchiveException::endOfFile);
			GlobalUnlock(*phBlob);
		}
	}
	else
	{
		if (*phBlob != NULL)
		{
			void* pvBlob = GlobalLock(*phBlob);
			ASSERT(pvBlob != NULL);
			cb = *(long*)pvBlob;
			ASSERT_BUFFER_VALID(pvBlob, sizeof(cb)+cb, FALSE);
			m_ar.Write(pvBlob, sizeof(cb)+cb);
			GlobalUnlock(*phBlob);
		}
		else
			m_ar << (DWORD)0;
	}
	return TRUE;
}

BOOL AFXAPI _AfxPeekAtClassIDInStream(LPSTREAM pstm, LPCLSID lpClassID)
{
	// Read the class ID, then restore the seek pointer.
	LARGE_INTEGER li;
	li.LowPart = (DWORD)(-(long)sizeof(CLSID));
	li.HighPart = -1;

	return (SUCCEEDED(ReadClassStm(pstm, lpClassID)) &&
		SUCCEEDED(pstm->Seek(li, STREAM_SEEK_CUR, NULL)));
}

BOOL AFXAPI _AfxIsSameUnknownObject(REFIID iid, LPUNKNOWN pUnk1, LPUNKNOWN pUnk2)
{
	if (pUnk1 == pUnk2)
		return TRUE;

	if (pUnk1 == NULL || pUnk2 == NULL)
		return FALSE;

	LPUNKNOWN pI1 = NULL;
	LPUNKNOWN pI2 = NULL;
	BOOL bResult = FALSE;
	if (SUCCEEDED(pUnk1->QueryInterface(iid, (void**)&pI1)))
	{
		ASSERT_POINTER(pI1, IUnknown);
		if (SUCCEEDED(pUnk2->QueryInterface(iid, (void**)&pI2)))
		{
			ASSERT_POINTER(pI2, IUnknown);
			bResult = (pI1 == pI2);
			pI2->Release();
		}
		pI1->Release();
	}
	return bResult;
}

BOOL CArchivePropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
		LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(ppUnk, LPUNKNOWN);
	ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);

	BOOL bResult = FALSE;
	CArchiveStream stm(&m_ar);

	if (m_bLoading)
	{
		RELEASE(*ppUnk);
		*ppUnk = NULL;

		BYTE bFlag;
		m_ar >> bFlag;
		if (bFlag != 0xFF)
		{
			// read the CLSID
			CLSID clsid;
			m_ar >> clsid.Data1;
			m_ar >> clsid.Data2;
			m_ar >> clsid.Data3;
			m_ar.Read(&clsid.Data4[0], sizeof clsid.Data4);

			// check for GUID_NULL first and skip if found
			if (IsEqualCLSID(clsid, GUID_NULL))
				bResult = TRUE;
			else
			{
				// otherwise will need a stream
				LPSTREAM pstm = _AfxGetArchiveStream(m_ar, stm);
				if (IsEqualCLSID(clsid, CLSID_StdPicture) ||
					IsEqualCLSID(clsid, CLSID_StdPicture_V1))
				{
					// special case for pictures
					bResult = SUCCEEDED(::OleLoadPicture(pstm, 0, FALSE, iid,
						(void**)ppUnk));
				}
				else
				{
					// otherwise, seek back to the CLSID
					LARGE_INTEGER li;
					li.LowPart = (DWORD)(-(long)sizeof(CLSID));
					li.HighPart = -1;
					VERIFY(SUCCEEDED(pstm->Seek(li, STREAM_SEEK_CUR, NULL)));

					// and load the object normally

					CLSID clsid;
					if (SUCCEEDED(::ReadClassStm(pstm, &clsid)) &&
							(SUCCEEDED(::CoCreateInstance(clsid, NULL,
								CLSCTX_SERVER | CLSCTX_REMOTE_SERVER,
								iid, (void**)ppUnk)) ||
							SUCCEEDED(::CoCreateInstance(clsid, NULL,
								CLSCTX_SERVER & ~CLSCTX_REMOTE_SERVER,
								iid, (void**)ppUnk))))
					{
						LPPERSISTSTREAM pps = NULL;
						if (SUCCEEDED((*ppUnk)->QueryInterface(
								IID_IPersistStream, (void**)&pps)) ||
							SUCCEEDED((*ppUnk)->QueryInterface(
								IID_IPersistStreamInit, (void**)&pps)))
						{
							ASSERT_POINTER(pps, IPersistStream);
							bResult = SUCCEEDED(pps->Load(pstm));
							pps->Release();
						}

						if (!bResult)
						{
							(*ppUnk)->Release();
							*ppUnk = NULL;
						}
					}
				}
			}
		}
		else
		{
			// Use default value.
			bResult = pUnkDefault == NULL ||
				SUCCEEDED(pUnkDefault->QueryInterface(iid, (LPVOID*)ppUnk));
		}
	}
	else
	{
		ASSERT_NULL_OR_POINTER(*ppUnk, IUnknown);

		// Check if *ppUnk and pUnkDefault are the same thing.  If so, don't
		// bother saving the object; just write a special flag instead.

		if (_AfxIsSameUnknownObject(iid, *ppUnk, pUnkDefault))
		{
			m_ar << (BYTE)0xFF;
			bResult = TRUE;
		}
		else
		{
			m_ar << (BYTE)0x00;
			if (*ppUnk != NULL)
			{
				LPPERSISTSTREAM pps = NULL;
				if (SUCCEEDED((*ppUnk)->QueryInterface(
						IID_IPersistStream, (void**)&pps)) ||
					SUCCEEDED((*ppUnk)->QueryInterface(
						IID_IPersistStreamInit, (void**)&pps)))
				{
					ASSERT_POINTER(pps, IPersistStream);
					LPSTREAM pstm = _AfxGetArchiveStream(m_ar, stm);
					bResult = SUCCEEDED(::OleSaveToStream(pps, pstm));
					pps->Release();
				}
			}
			else
			{
				// If no object, write null class ID.
				m_ar.Write(&GUID_NULL, sizeof(GUID));
			}
		}
	}

	// throw exception in case of unthrown errors
	if (!bResult)
		AfxThrowArchiveException(CArchiveException::generic);

	return TRUE;
}

BOOL CArchivePropExchange::ExchangeFontProp(LPCTSTR pszPropName,
	CFontHolder& font, const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&font, CFontHolder);
	ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
	ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);

	BOOL bResult = FALSE;
	CArchiveStream stm(&m_ar);
	LPFONT pFont;

	if (m_bLoading)
	{
		BYTE bFlag;
		m_ar >> bFlag;
		if (bFlag != 0xFF)
		{
			LPSTREAM pstm = _AfxGetArchiveStream(m_ar, stm);
			pFont = _AfxCreateFontFromStream(pstm);
			if (pFont != NULL)
			{
				font.SetFont(pFont);
				bResult = TRUE;
			}
		}
		if (!bResult)
		{
			font.InitializeFont(pFontDesc, pFontDispAmbient);
			bResult = TRUE;
		}
	}
	else
	{
		pFont = font.m_pFont;
		if (pFont != NULL)
		{
			// If same as ambient font (or error), write 0xFF for the flag
			if (!_AfxIsSameFont(font, pFontDesc, pFontDispAmbient))
			{
				LPPERSISTSTREAM pps = NULL;
				if (SUCCEEDED(pFont->QueryInterface(IID_IPersistStream,
					(LPVOID*)&pps)))
				{
					ASSERT_POINTER(pps, IPersistStream);
					m_ar << (BYTE)0x00;
					LPSTREAM pstm = _AfxGetArchiveStream(m_ar, stm);
					bResult = SUCCEEDED(::OleSaveToStream(pps, pstm));
					pps->Release();
					if (!bResult)
						AfxThrowArchiveException(CArchiveException::generic);
				}
			}
		}
		if (!bResult)
		{
			m_ar << (BYTE)0xFF;
			bResult = TRUE;
		}
	}
	return bResult;
}

/////////////////////////////////////////////////////////////////////////////
// CResetPropExchange member functions

CResetPropExchange::CResetPropExchange()
{
	m_bLoading = TRUE;
}

BOOL CResetPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
		void* pvProp, const void* pvDefault)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT(AfxIsValidAddress(pvProp, 1, FALSE));
	ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE));

	return _AfxCopyPropValue(vtProp, pvProp, pvDefault);
}

BOOL CResetPropExchange::ExchangeBlobProp(LPCTSTR pszPropName,
	HGLOBAL* phBlob, HGLOBAL hBlobDefault)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(phBlob, HGLOBAL);

	// free the previous memory block
	if (*phBlob != NULL)
	{
		GlobalFree(*phBlob);
		*phBlob = NULL;
	}

	// copy the memory block
	BOOL bResult = TRUE;
	if (hBlobDefault != NULL)
		bResult = _AfxCopyBlob(phBlob, hBlobDefault);
	return bResult;
}

BOOL CResetPropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
		LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(ppUnk, LPUNKNOWN);
	ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);

	RELEASE(*ppUnk);

	BOOL bResult = TRUE;
	if (pUnkDefault != NULL)
	{
		bResult = SUCCEEDED(pUnkDefault->QueryInterface(iid,
			(LPVOID*)ppUnk));
	}
	return bResult;
}

BOOL CResetPropExchange::ExchangeFontProp(
	LPCTSTR pszPropName, CFontHolder& font, const FONTDESC* pFontDesc,
	LPFONTDISP pFontDispAmbient)
{
	UNUSED(pszPropName);     // unused in release builds

	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&font, CFontHolder);
	ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
	ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);

	font.InitializeFont(pFontDesc, pFontDispAmbient);
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CAsyncPropExchange member functions

CAsyncPropExchange::CAsyncPropExchange(DWORD dwVersion)
{
	m_bAsync = TRUE;
	m_bLoading = TRUE;
	m_dwVersion = dwVersion;
}

BOOL CAsyncPropExchange::ExchangeVersion(DWORD& dwVersionLoaded,
	DWORD dwVersionDefault, BOOL bConvert)
{
	if (m_bLoading)
	{
		dwVersionLoaded = m_dwVersion;
		return TRUE;
	}
	else
	{
		return m_dwVersion == (bConvert ? dwVersionDefault : dwVersionLoaded);
	}
}

BOOL CAsyncPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
	void* pvProp, const void* pvDefault)
{
	// Should never be called
	UNUSED_ALWAYS(pszPropName);
	UNUSED_ALWAYS(vtProp);
	UNUSED_ALWAYS(pvProp);
	UNUSED_ALWAYS(pvDefault);
	ASSERT(FALSE);
	return FALSE;
}

BOOL CAsyncPropExchange::ExchangeBlobProp(LPCTSTR pszPropName, HGLOBAL* phBlob,
	HGLOBAL hBlobDefault)
{
	// Should never be called
	UNUSED_ALWAYS(pszPropName);
	UNUSED_ALWAYS(phBlob);
	UNUSED_ALWAYS(hBlobDefault);
	ASSERT(FALSE);
	return FALSE;
}

BOOL CAsyncPropExchange::ExchangeFontProp(LPCTSTR pszPropName,
	CFontHolder& font, const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient)
{
	// Should never be called
	UNUSED_ALWAYS(pszPropName);
	UNUSED_ALWAYS(font);
	UNUSED_ALWAYS(pFontDesc);
	UNUSED_ALWAYS(pFontDispAmbient);
	ASSERT(FALSE);
	return FALSE;
}

BOOL CAsyncPropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
	LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
{
	// Should never be called
	UNUSED_ALWAYS(pszPropName);
	UNUSED_ALWAYS(ppUnk);
	UNUSED_ALWAYS(iid);
	UNUSED_ALWAYS(pUnkDefault);
	ASSERT(FALSE);
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// PX_ functions

BOOL AFX_CDECL PX_Short(CPropExchange* pPX, LPCTSTR pszPropName, short& sValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&sValue, short);

	if (pPX->IsAsynchronous())
		return TRUE;
	return  pPX->ExchangeProp(pszPropName, VT_I2, &sValue);
}

BOOL AFX_CDECL PX_Short(CPropExchange* pPX, LPCTSTR pszPropName, short& sValue,
	short sDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&sValue, short);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I2, &sValue, &sDefault);
}

BOOL AFX_CDECL PX_UShort(CPropExchange* pPX, LPCTSTR pszPropName, USHORT& usValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&usValue, USHORT);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I2, &usValue);
}

BOOL AFX_CDECL PX_UShort(CPropExchange* pPX, LPCTSTR pszPropName, USHORT& usValue,
	USHORT usDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&usValue, USHORT);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I2, &usValue, &usDefault);
}

BOOL AFX_CDECL PX_Long(CPropExchange* pPX, LPCTSTR pszPropName, long& lValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&lValue, long);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I4, &lValue);
}

BOOL AFX_CDECL PX_Long(CPropExchange* pPX, LPCTSTR pszPropName, long& lValue,
	long lDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&lValue, long);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I4, &lValue, &lDefault);
}

BOOL AFX_CDECL PX_ULong(CPropExchange* pPX, LPCTSTR pszPropName, ULONG& ulValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&ulValue, ULONG);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I4, &ulValue);
}

BOOL AFX_CDECL PX_ULong(CPropExchange* pPX, LPCTSTR pszPropName, ULONG& ulValue,
	ULONG ulDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&ulValue, ULONG);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I4, &ulValue, &ulDefault);
}

BOOL AFX_CDECL PX_Color(CPropExchange* pPX, LPCTSTR pszPropName, OLE_COLOR& clrValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&clrValue, OLE_COLOR);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I4, &clrValue);
}

BOOL AFX_CDECL PX_Color(CPropExchange* pPX, LPCTSTR pszPropName, OLE_COLOR& clrValue,
	OLE_COLOR clrDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&clrValue, OLE_COLOR);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_I4, &clrValue, &clrDefault);
}

BOOL AFX_CDECL PX_Bool(CPropExchange* pPX, LPCTSTR pszPropName, BOOL& bValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&bValue, BOOL);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_BOOL, &bValue);
}

BOOL AFX_CDECL PX_Bool(CPropExchange* pPX, LPCTSTR pszPropName, BOOL& bValue,
	BOOL bDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&bValue, BOOL);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_BOOL, &bValue, &bDefault);
}

BOOL AFX_CDECL PX_String(CPropExchange* pPX, LPCTSTR pszPropName, CString& strValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&strValue, CString);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_BSTR, &strValue);
}

BOOL AFX_CDECL PX_String(CPropExchange* pPX, LPCTSTR pszPropName, CString& strValue,
	const CString& strDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&strValue, CString);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_BSTR, &strValue, &strDefault);
}

BOOL AFX_CDECL PX_String(CPropExchange* pPX, LPCTSTR pszPropName, CString& strValue,
	LPCTSTR lpszDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&strValue, CString);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_LPSTR, &strValue, lpszDefault);
}

BOOL AFX_CDECL PX_Currency(CPropExchange* pPX, LPCTSTR pszPropName, CY& cyValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&cyValue, CY);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_CY, &cyValue);
}

BOOL AFX_CDECL PX_Currency(CPropExchange* pPX, LPCTSTR pszPropName, CY& cyValue,
	CY cyDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&cyValue, CY);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_CY, &cyValue, &cyDefault);
}

BOOL AFX_CDECL PX_Float(CPropExchange* pPX, LPCTSTR pszPropName, float& floatValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&floatValue, float);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_R4, &floatValue);
}

BOOL AFX_CDECL PX_Float(CPropExchange* pPX, LPCTSTR pszPropName, float& floatValue,
	float floatDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&floatValue, float);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_R4, &floatValue, &floatDefault);
}

BOOL AFX_CDECL PX_Double(CPropExchange* pPX, LPCTSTR pszPropName, double& doubleValue)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&doubleValue, double);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_R8, &doubleValue);
}

BOOL AFX_CDECL PX_Double(CPropExchange* pPX, LPCTSTR pszPropName, double& doubleValue,
	double doubleDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&doubleValue, double);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeProp(pszPropName, VT_R8, &doubleValue, &doubleDefault);
}

BOOL AFX_CDECL PX_Blob(CPropExchange* pPX, LPCTSTR pszPropName, HGLOBAL& hBlob,
	HGLOBAL hBlobDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&hBlob, HGLOBAL);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeBlobProp(pszPropName, &hBlob, hBlobDefault);
}

BOOL AFX_CDECL PX_Font(CPropExchange* pPX, LPCTSTR pszPropName, CFontHolder& font,
		const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&font, CFontHolder);
	ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
	ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangeFontProp(pszPropName, font, pFontDesc,
		pFontDispAmbient);
}

BOOL AFX_CDECL PX_IUnknown(CPropExchange* pPX, LPCTSTR pszPropName, LPUNKNOWN& pUnk,
	REFIID iid, LPUNKNOWN pUnkDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&pUnk, LPUNKNOWN);
	ASSERT_NULL_OR_POINTER(pUnk, IUnknown);
	ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);

	if (pPX->IsAsynchronous())
		return TRUE;
	return pPX->ExchangePersistentProp(pszPropName, &pUnk, iid, pUnkDefault);
}

BOOL AFX_CDECL PX_Picture(CPropExchange* pPX, LPCTSTR pszPropName, CPictureHolder& pict)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&pict, CPictureHolder);

	if (pPX->IsAsynchronous())
		return TRUE;
	LPUNKNOWN& pUnk = (LPUNKNOWN&)pict.m_pPict;
	return PX_IUnknown(pPX, pszPropName, pUnk, IID_IPicture);
}

BOOL AFX_CDECL PX_Picture(CPropExchange* pPX, LPCTSTR pszPropName, CPictureHolder& pict,
	CPictureHolder& pictDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));
	ASSERT_POINTER(&pict, CPictureHolder);

	if (pPX->IsAsynchronous())
		return TRUE;
	LPUNKNOWN& pUnk = (LPUNKNOWN&)pict.m_pPict;
	return PX_IUnknown(pPX, pszPropName, pUnk, IID_IPicture,
		pictDefault.m_pPict);
}

BOOL AFX_CDECL PX_VBXFontConvert(CPropExchange* pPX, CFontHolder& font)
{
	USES_CONVERSION;

	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT_POINTER(&font, CFontHolder);

	if (pPX->IsAsynchronous())
		return TRUE;
	if (font.m_pFont != NULL)
	{
		CString strName;
		if (PX_String(pPX, _T("FontName"), strName))
		{
			BSTR bstrName;
			bstrName = SysAllocString(T2COLE(strName));
			font.m_pFont->put_Name(bstrName);
			SysFreeString(bstrName);
		}

		CY cySize;
		if (PX_Currency(pPX, _T("FontSize"), cySize))
			font.m_pFont->put_Size(cySize);

		BOOL bFlag;
		if (PX_Bool(pPX, _T("FontBold"), bFlag))
			font.m_pFont->put_Bold(bFlag);
		if (PX_Bool(pPX, _T("FontItalic"), bFlag))
			font.m_pFont->put_Italic(bFlag);
		if (PX_Bool(pPX, _T("FontUnderline"), bFlag))
			font.m_pFont->put_Underline(bFlag);
		if (PX_Bool(pPX, _T("FontStrikethru"), bFlag))
			font.m_pFont->put_Strikethrough(bFlag);
	}
	return TRUE;
}

#ifndef _MAC

static
BOOL _afxPX_DataPath(CPropExchange* pPX, LPCTSTR pszPropName,
	CDataPathProperty& dataPathProp, VARTYPE vtDefault, const void* pvDefault)
{
	ASSERT_POINTER(pPX, CPropExchange);
	ASSERT(AfxIsValidString(pszPropName));

	const BOOL bIsLoading = pPX->IsLoading();

	COleControl* pControl = dataPathProp.GetControl();
	if (!pControl)
		TRACE0("No control in PX_DataPath!");

	BOOL bHasClientSite = pControl ? NULL != pControl->GetClientSite() : FALSE;

	if (!pPX->IsAsynchronous())
	{
		CString strPath;
		if (!bIsLoading)
			strPath = dataPathProp.GetPath();
		if (((pvDefault != NULL) && !pPX->ExchangeProp(pszPropName, vtDefault, &strPath, pvDefault)) ||
			((pvDefault == NULL) && !pPX->ExchangeProp(pszPropName, VT_BSTR, &strPath)))
			return FALSE;
		if (bIsLoading)
			dataPathProp.SetPath(strPath);
		COleControl* pControl = dataPathProp.GetControl();
		if (pControl && !bHasClientSite)
			pControl->RequestAsynchronousExchange(pPX->GetVersion());
	}

	if (pPX->IsAsynchronous() || bHasClientSite)
	{
	#ifdef _DEBUG
		{
			if (!bHasClientSite)
				TRACE0("No client site in PX_DataPath!");
		}
	#endif // _DEBUG

		if (bIsLoading)
			return dataPathProp.Open();
	}

	return TRUE;
}

BOOL AFX_CDECL PX_DataPath(CPropExchange* pPX, LPCTSTR pszPropName,
	CDataPathProperty& dataPathProp, LPCTSTR pszDefault)
{
	return _afxPX_DataPath(pPX, pszPropName, dataPathProp, VT_LPSTR, pszDefault);
}

BOOL AFX_CDECL PX_DataPath(CPropExchange* pPX, LPCTSTR pszPropName,
	CDataPathProperty& dataPathProp, const CString& strDefault)
{
	return _afxPX_DataPath(pPX, pszPropName, dataPathProp, VT_BSTR, strDefault);
}

#endif // !_MAC

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

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif