/************************************************************************
**	_ D B D A O . H													*
**																		*
*************************************************************************
** Copyright (C) 1996 by Microsoft Corporation		 			*
**		   All Rights Reserved					 						*
************************************************************************/
/*
	_DBDAO.H

	Internal definitions and prototypes for dbdao C++ classes
*/
#ifndef __DBDAO_H_
#define __DBDAO_H_


/*****************************************************************************
* Forwards
*/
class COleVariant;
class CdbBookmark;
class CdbException;
class CdbOleObject;
class CdbObject;
class CdbError;
class CdbProperty;
class CdbDBEngine;
class CdbWorkspace;
class CdbDatabase;
class CdbConnection;
class CdbRecordset;
class CdbGetRowsEx;
class CdbQueryDef;
class CdbTableDef;
class CdbField;
class CdbRelation;
class CdbIndex;
class CdbUser;
class CdbGroup;
class CdbDocument;
class CdbContainer;
class CdbParameter;
class CdbCollection;
class CdbErrors;
class CdbProperties;
class CdbWorkspaces;
class CdbDatabases;
class CdbConnections;
class CdbRecordsets;
class CdbQueryDefs;
class CdbTableDefs;
class CdbFields;
class CdbRelations;
class CdbIndexes;
class CdbUsers;
class CdbGroups;
class CdbDocuments;
class CdbContainers;
class CdbParameters;
class CdbBStr;

/*****************************************************************************
* DAO runtime key
*/
const char szKEY[] = "mbmabptebkjcdlgtjmskjwtsdhjbmkmwtrak";

/*****************************************************************************
* Miscellaneous defines
*/
#define DAO_MAXSEEKFIELDS 13


/*****************************************************************************
* CdbBSTR (OLE BSTR helper)
*/
class DLLEXPORT CdbBSTR
	{
	public:
	CONSTRUCTOR			CdbBSTR				(BSTR=NULL);
	DESTRUCTOR			~CdbBSTR			(VOID);

	operator			BSTR *				(VOID);
	operator			LPCTSTR				(VOID);

	private:
	BSTR				m_bstr;
	};

/*****************************************************************************
* CdbVariant (OLE Variant helper)
*/
class CdbVariant : public COleVariant
	{
	public:
	CONSTRUCTOR						CdbVariant						(LONG l);
	CONSTRUCTOR                     CdbVariant                      (VOID);
	CONSTRUCTOR                     CdbVariant                      (LPCTSTR pstr);
	CONSTRUCTOR                     CdbVariant                      (SHORT s, BOOL bIsBool = FALSE);
	CONSTRUCTOR                     CdbVariant                      (LPVARIANT pv);
	CONSTRUCTOR                     CdbVariant                      (LPSAFEARRAY psa);

	VOID                            operator =                      (LPVARIANT pv);
	VOID                            operator =                      (LPCTSTR pstr);
	VOID                            operator =                      (SHORT s);
	VOID                            operator =                      (const int i);
	VOID                            operator =                      (LONG l);
	};

inline CONSTRUCTOR	CdbVariant::CdbVariant(
	VOID) : COleVariant()
	{
	vt		= VT_ERROR;
	scode	= DISP_E_PARAMNOTFOUND;
	}

inline CdbVariant::CdbVariant (LONG l)
{
		if (l == -1)		
			{	
			vt		= VT_ERROR;
			scode	= DISP_E_PARAMNOTFOUND;
			}
		else
			{
			vt		= VT_I4;
			lVal	= l;
			}
}


inline CONSTRUCTOR	CdbVariant::CdbVariant(
	LPCTSTR pstr): COleVariant(pstr,VT_BSTRT)
	{
	if (!pstr)
		{
		VariantClear(this);
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	}


inline CONSTRUCTOR	CdbVariant::CdbVariant(
	SHORT s, BOOL bIsBool) : COleVariant(s)
	{
	if (bIsBool)
		{
		vt		= VT_BOOL;
		boolVal	= s;
		}
	else if (s==-1)
		{
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	}

inline CONSTRUCTOR	CdbVariant::CdbVariant(
	LPVARIANT	pv)
	{
	if (!pv)
		{
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		VariantCopy(this, pv);
	}

inline CONSTRUCTOR	CdbVariant::CdbVariant(
	LPSAFEARRAY psa)
	{
	if (!psa)
		{
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		{
		vt		= VT_ARRAY|VT_UI1;
		parray	= psa;
		}
	}

inline VOID	CdbVariant::operator =(
	LPVARIANT pv)
	{
	if (!pv)
		{
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		VariantCopy(this, pv);
	}

inline VOID	CdbVariant::operator =(
	LPCTSTR pstr) 
	{
	if (!pstr)
		{
		VariantClear(this);
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		{
#ifdef UNICODE
		bstrVal = SysAllocString(pstr);
#else
		bstrVal = SysAllocStringByteLen(pstr, strlen(pstr));
#endif
		vt = VT_BSTR;
		}
	}


inline VOID	CdbVariant::operator =(
	SHORT s)
	{
	if (s==-1)
		{
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		{
		vt		= VT_I2;
		iVal	= s;
		}
	}

inline VOID	CdbVariant::operator =(
	const int i)
	{
	if (i==-1)
		{
		vt		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		{
		vt		= VT_I2;
		iVal	= (SHORT)i;
		}
	}


inline VOID	CdbVariant::operator =(
	LONG 	l)
	{
	if (l==-1)
		{
		vt 		= VT_ERROR;
		scode	= DISP_E_PARAMNOTFOUND;
		}
	else
		{
		vt		= VT_I4;
		lVal	= l;
		}
	}


/*****************************************************************************
* CdbWide
*/
HRESULT	CdbWideFromAnsi(LPSTR, unsigned int, BSTR *);

class CdbWide
	{
	public:
	CONSTRUCTOR			CdbWide				(LPSTR pstr, unsigned int cb=0)
		{
		CdbWideFromAnsi(pstr, (pstr ? (cb==0 ? strlen(pstr) : cb) : 0), &m_bstr);
		}
	DESTRUCTOR			~CdbWide			()
		{
		SysFreeString(m_bstr);
		}

	operator			LPWSTR					()
		{
		return (LPWSTR)m_bstr;
		}
	operator			LPSTR					()
		{
		return (LPSTR)m_bstr;
		}

	ULONG				cBytes					()
		{
		return SysStringByteLen(m_bstr);
		}

	private:
	BSTR				m_bstr;
	};


/*****************************************************************************
* CdbOleObject
*/
class DLLEXPORT CdbOleObject : public CObject
	{
	public:
	CONSTRUCTOR                             CdbOleObject            (VOID);
	virtual DESTRUCTOR						~CdbOleObject           (VOID);
	BOOL                                    Exists                  (VOID);
	CdbOleObject &							operator =              (CdbOleObject &o);
											operator LPUNKNOWN		(){ return GetInterface();}
	VOID                                    SetInterface            (LPUNKNOWN punk, BOOL bAddRef=FALSE);
	VOID                                    SetInterface            (REFIID riidClass, REFIID riidInterface);
	VOID                                    SetInterfaceLic         (REFIID riidClass, REFIID riidInterface);
	LPUNKNOWN								GetInterface            (BOOL bAddRef=FALSE, BOOL bThrowException=TRUE) const;

	virtual VOID							OnInterfaceChange       (VOID);
	VOID                                    SetRichErrorInfo        (LPOLESTR pstrSource, LPOLESTR pstrDescription, LPOLESTR pstrHelpFile, ULONG ulHelpID) const;

	protected:
	BOOL                                    StartOLE                        (VOID);
	LPUNKNOWN                               m_punkInterface;
	};



/*****************************************************************************
* CdbCollection
*/
class DLLEXPORT CdbCollection : public CdbOleObject
	{
	public:

	// Methods
	virtual CdbObject               ObItem                  (LONG i) = 0;
	virtual CdbObject               ObItem                  (LPCTSTR pstr) = 0;
	virtual LONG                    GetCount                (VOID) = 0;
	virtual VOID                    ObAppend                (CdbObject &obj) = 0;
	virtual VOID                    Delete                  (LPCTSTR pstr) = 0;
	virtual VOID                    Refresh                 (VOID) = 0;
	};

class DLLEXPORT CdbStaticCollection : public CdbCollection
	{
	public:
	CdbObject                               ObItem                  (LONG i);
	CdbObject                               ObItem                  (LPCTSTR pstr);
	LONG                                    GetCount                (VOID);
	VOID                                    ObAppend                (CdbObject &obj);
	VOID                                    Delete                  (LPCTSTR pstr);
	VOID                                    Refresh                 (VOID) ;
	};

class DLLEXPORT CdbDynamicCollection : public CdbCollection
	{
	public:
	CdbObject                               ObItem                  (LONG i);
	CdbObject                               ObItem                  (LPCTSTR pstr);
	LONG                                    GetCount                (VOID);
	VOID                                    ObAppend                (CdbObject &obj);
	VOID                                    Delete                  (LPCTSTR pstr);
	VOID                                    Refresh                 (VOID);
	};

#define DAOMFC_STATIC_COLLECTION_DECL(objColl, objSingle, intSingle)    \
	class DLLEXPORT objColl : public CdbStaticCollection                                                    \
		{                                                                                                                               \
		public:                                                                                                                 \
																		\
		objSingle                       Item                            (LONG i);                               \
		objSingle                       Item                            (LPCTSTR pstr);                 \
		objSingle                       operator[]                      (LONG i);                               \
		objSingle                       operator[]                      (LPCTSTR pstr);                 \
		}

#define DAOMFC_DYNAMIC_COLLECTION_DECL(objColl, objSingle, intSingle)   \
	class DLLEXPORT objColl : public CdbDynamicCollection                                                   \
		{                                                                                                                               \
		public:                                                                                                                 \
																		\
		objSingle                       Item                            (LONG i);                               \
		objSingle                       Item                            (LPCTSTR pstr);                 \
		VOID                            Append                          (objSingle &o);                 \
		objSingle                       operator[]                      (LONG i);                               \
		objSingle                       operator[]                      (LPCTSTR pstr);                 \
		}

DAOMFC_STATIC_COLLECTION_DECL(CdbErrors, CdbError, DAOError);
DAOMFC_STATIC_COLLECTION_DECL(CdbDatabases, CdbDatabase, DAODatabase);
//Connections are special cased so we can trap the copy constructor
DAOMFC_STATIC_COLLECTION_DECL(CdbRecordsets, CdbRecordset, DAORecordset);
DAOMFC_STATIC_COLLECTION_DECL(CdbParameters, CdbParameter, DAOParameter);
DAOMFC_STATIC_COLLECTION_DECL(CdbDocuments, CdbDocument, DAODocument);
DAOMFC_STATIC_COLLECTION_DECL(CdbContainers, CdbContainer, DAOContainer);

DAOMFC_DYNAMIC_COLLECTION_DECL(CdbProperties, CdbProperty, DAOProperty);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbFields, CdbField, DAOField);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbQueryDefs, CdbQueryDef, DAOQueryDef);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbTableDefs, CdbTableDef, DAOTableDef);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbIndexes, CdbIndex, DAOIndex);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbRelations, CdbRelation, DAORelation);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbUsers, CdbUser, DAOUser);
DAOMFC_DYNAMIC_COLLECTION_DECL(CdbGroups, CdbGroup, DAOGroup);

//Need some extra functions in CdbWorkspaces to support the delay in creating the 
//default workspace needed to support the JET/ODBC option.
class DLLEXPORT CdbWorkspaces : public CdbDynamicCollection
	{        
	friend CdbDBEngine;
	private:
	DAODBEngine	*					pDBEng;
	BOOL							m_bDontStart;

	public:                                                                                                                 
	CONSTRUCTOR                     CdbWorkspaces			(VOID){pDBEng = NULL;}
	CdbWorkspace                    Item                    (LONG i);                               
	CdbWorkspace                    Item                    (LPCTSTR pstr);                 
	VOID                            Append                  (CdbWorkspace &o);                 
	CdbWorkspace                    operator[]              (LONG i);                         
	CdbWorkspace                    operator[]              (LPCTSTR pstr);                
	VOID                            SetDBEngine	            (DAODBEngine	*peng){pDBEng = peng;}
	VOID	                        GetDelayedInterface     ();
	};

//Need to trap Connections in the copy constructor so the user can't
//get a "sorta-kinda" working Connections collection on a Jet workspace
class DLLEXPORT CdbConnections : public CdbStaticCollection
	{        
	public:
	CONSTRUCTOR						CdbConnections			(CdbConnections &Connections);
	CONSTRUCTOR						CdbConnections			(){pwrk = NULL;}
	CdbConnection                   Item                    (LONG i);                               
	CdbConnection                   Item                    (LPCTSTR pstr);                 
	CdbConnection                   operator[]              (LONG i);                               
	CdbConnection                   operator[]              (LPCTSTR pstr);               
	CdbConnections	&				operator =				(CdbConnections &o);
	LONG                            GetCount                (VOID);
	VOID                            Refresh                 (VOID) ;
	VOID							SetWorkspace			(DAOWorkspace * pParent){pwrk = pParent;}			

	private:
	VOID							CheckInterface();
	DAOWorkspace *					pwrk;
	};

/*****************************************************************************
* CdbObject
*/
class DLLEXPORT CdbObject : public CdbOleObject
	{
	public:
	CONSTRUCTOR                             CdbObject                       (VOID);
	CONSTRUCTOR                             CdbObject                       (LPUNKNOWN punk, BOOL bAddRef=FALSE);

	virtual CString                 GetName                         (VOID); 
	virtual VOID                    SetName                         (LPCTSTR pstr);

	CdbProperties                   Properties;
	};



/*****************************************************************************
* CdbGetRowsEx  (holds GetRowsEx for Recordset)
*/

class DLLEXPORT CdbGetRowsEx : public CdbObject
	{
	public:

	// Administration
	CONSTRUCTOR                     CdbGetRowsEx            (VOID);
	CONSTRUCTOR                     CdbGetRowsEx            (ICDAORecordset *pGetRows, BOOL bAddRef=FALSE);
	CONSTRUCTOR                     CdbGetRowsEx            (const CdbGetRowsEx &);
	CdbGetRowsEx &          operator =                      (const CdbGetRowsEx &);
	VOID                            OnInterfaceChange       (VOID);

	};

/*****************************************************************************
* Helper macros
*/

//Initialize a variant
#define DAOVINIT(var)						\
	do										\
		{									\
		(var).vt	= VT_ERROR;				\
		(var).scode	= DISP_E_PARAMNOTFOUND;	\
		}									\
	while (0)


// LPTSTR to VARIANT
#define STV(pstr)	CdbVariant(pstr)

// LPTSTR to BSTR
#define STB(pstr)	V_BSTR(((LPVARIANT)STV(pstr)))

// LONG to VARIANT
#define LTV(l)		CdbVariant(l)

// Optional LONG to VARIANT
#define OLTV(l)		CdbVariant((l))

// C/C++ bool to DAO bool
#define BTB(b)		((VARIANT_BOOL)(b?-1:0))

// C/C++ bool to VARIANT
#define BTV(b)		CdbVariant(BTB(b), TRUE)

// C/C++ short to VARIANT
#define SHTV(s)		CdbVariant((SHORT)s)

// OLE variant to VARIANT
#define VTV(pv)		CdbVariant(pv)

// SAFEARRAY to VARIANT
#define ATV(psa, var)								\
	do												\
		{											\
		if (!psa)									\
			{										\
			var.vt		= VT_ERROR;					\
			var.scode	= DISP_E_PARAMNOTFOUND;		\
			}										\
		else										\
			{										\
			var.vt		= VT_ARRAY|VT_UI1;			\
			SafeArrayCopy(psa, &var.parray);	\
			}										\
		}											\
	while (0)

#define DAOMFC_CALL(hr)						\
	do \
	{ \
    HRESULT  hresult = (hr);           \
		if(FAILED(hresult)) \
		{ \
			TRACE0("\nDBDAO Call Failed.\n\t"); \
			TRACE2("\nIn file %s on line %d\n", _T("DBDAO.CPP"), __LINE__); \
			TRACE1("hResult = %X\n", hresult); \
			if (GetScode(hresult) == E_OUTOFMEMORY) \
				AfxThrowMemoryException(); \
			else \
				throw CdbException(hresult); \
		} \
	} while (0)


/*****************************************************************************
* Property Set/Get helper macros
*/

// Get a LONG property
#define LPROPGET(intDAO, meth)						\
	do												\
		{											\
		intDAO *	p	= (intDAO *)GetInterface();	\
		LONG		l	= 0;						\
													\
		DAOMFC_CALL(p->meth(&l));					\
													\
		return l;									\
		}											\
	while (0)

// Set a LONG property
#define LPROPSET(intDAO, meth, l)					\
	do												\
		{											\
		intDAO *	p = (intDAO *)GetInterface();	\
													\
		DAOMFC_CALL(p->meth(l));					\
		}											\
	while(0)

// Get a SHORT property
#define WPROPGET(intDAO, meth)						\
	do												\
		{											\
		intDAO *	p	= (intDAO *)GetInterface();	\
		SHORT		s	= 0;						\
													\
		DAOMFC_CALL(p->meth(&s));					\
													\
		return s;									\
		}											\
	while (0)

// Set a SHORT property
#define WPROPSET(intDAO, meth, s)					\
	do												\
		{											\
		intDAO *	p = (intDAO *)GetInterface();	\
													\
		DAOMFC_CALL(p->meth(s));					\
		}											\
	while(0)

// Get a STRING property
#define SPROPGET(intDAO, meth)						\
	do												\
		{											\
		intDAO *	p	= (intDAO *)GetInterface();	\
		CdbBSTR		bstr;							\
													\
		DAOMFC_CALL(p->meth(bstr));					\
													\
		return bstr;								\
		}											\
	while (0)

// Set a STRING property
#define SPROPSET(intDAO, meth, s)					\
	do												\
		{											\
		intDAO *	p = (intDAO *)GetInterface();	\
													\
		DAOMFC_CALL(p->meth(STB(s)));				\
		}											\
	while(0)

// Get a DATETIME property
#define DPROPGET(intDAO, meth)						\
	do												\
		{											\
		intDAO *	p	= (intDAO *)GetInterface();	\
		VARIANT 	Var;								\
													\
		VariantInit(&Var);							\
		DAOMFC_CALL(p->meth(&Var));					\
		return Var;									\
		}											\
	while (0)

// Set a DATETIME property
#define DPROPSET(intDAO, meth, pv)					\
	do												\
		{											\
		intDAO *	p = (intDAO *)GetInterface();	\
													\
		DAOMFC_CALL(p->meth(*pv));					\
		}											\
	while(0)

// Get a BOOLEAN property
#define BPROPGET(intDAO, meth)							\
	do													\
		{												\
		intDAO *		p	= (intDAO *)GetInterface();	\
		VARIANT_BOOL	vb	= 0;						\
														\
		DAOMFC_CALL(p->meth(&vb));						\
														\
		return (BOOL)vb;								\
		}												\
	while (0)

// Set a BOOLEAN property
#define BPROPSET(intDAO, meth, b)						\
	do													\
		{												\
		intDAO *	p = (intDAO *)GetInterface();		\
														\
		DAOMFC_CALL(p->meth(BTB(b)));					\
		}												\
	while(0)

// Get a VARIANT property
#define VPROPGET(intDAO, meth)						\
	do												\
		{											\
		intDAO *	p	= (intDAO *)GetInterface();	\
		COleVariant 	v;								\
													\
		VariantInit(&v);							\
		DAOMFC_CALL(p->meth(&v));					\
													\
		return &v;									\
		}											\
	while (0)

// Set a VARIANT property
#define VPROPSET(intDAO, meth, pv)					\
	do												\
		{											\
		intDAO *	p = (intDAO *)GetInterface();	\
													\
		DAOMFC_CALL(p->meth(*pv));					\
		}											\
	while(0)

// Get a DWORD property
#define DWPROPGET(intDAO, meth)						\
	do												\
		{											\
		intDAO *	p	= (intDAO *)GetInterface();	\
		DWORD		dw	= 0;						\
													\
		DAOMFC_CALL(p->meth(&dw));					\
													\
		return dw;									\
		}											\
	while (0)


#define DAOMFC_STATIC_COLLECTION_IMPL(objColl, objSingle, intColl, intSingle)													 \
		objSingle			objColl::Item				(LONG i) 		{ return (intSingle *)(ObItem(i).GetInterface(TRUE)); }	 \
		objSingle			objColl::Item				(LPCTSTR pstr)	{ return (intSingle *)(ObItem(pstr).GetInterface(TRUE)); } \
		objSingle			objColl::operator[]			(LONG i)		{ return (intSingle *)(Item(i).GetInterface(TRUE)); } \
		objSingle			objColl::operator[]			(LPCTSTR pstr)	{ return (intSingle *)(Item(pstr).GetInterface(TRUE)); }

#define DAOMFC_DYNAMIC_COLLECTION_IMPL(objColl, objSingle, intColl, intSingle)													 \
		objSingle			objColl::Item				(LONG i) 		{ return (intSingle *)(ObItem(i).GetInterface(TRUE)); }	 \
		objSingle			objColl::Item				(LPCTSTR pstr)	{ return (intSingle *)(ObItem(pstr).GetInterface(TRUE)); } \
		VOID				objColl::Append				(objSingle &o)	{ ObAppend(o); } \
		objSingle			objColl::operator[]			(LONG i)		{ return (intSingle *)(Item(i).GetInterface(TRUE)); } \
		objSingle			objColl::operator[]			(LPCTSTR pstr)	{ return (intSingle *)(Item(pstr).GetInterface(TRUE)); }

DECLARE_INTERFACE_(DAOMFCSCollection, _DAOCollection)
{
STDMETHOD(get_Item)		(VARIANT index, LPUNKNOWN *ppunk);
};

DECLARE_INTERFACE_(DAOMFCDCollection, _DAODynaCollection)
{
STDMETHOD(get_Item)		(VARIANT index, LPUNKNOWN *ppunk);
};


#endif // __DBDAO_H_ 
