text: //--------------------------------------------------------------------
  // Microsoft OLE DB Test
  //
  // Copyright (C) 1995-2000 Microsoft Corporation
  //
  // @doc
  //
  // @module ExtraLib.h    | This module contains header information for 
  //	    					ExtraLib.cpp general testing library
  //
  // @rev 01 | 02-22-96 | Microsoft | Created
  // @rev 02 | 12-01-96 | Microsoft | Updated
  //
  
  #ifndef _EXTRALIB_H_
  #define _EXTRALIB_H_
  
  #include "oledb.h" 			// MS (OLE DB) Header Files
  #include "oledberr.h"		// MS (OLE DB) Errors 
  #include <msdasql.h>		// MS (OLE DB) Extra GUIDs (KAGPROP_QUERYBASEDUPDATES)
  #include <msdaguid.h>		// MS (OLE DB) IRowPosition
  
  #include "privlib.h"		// Private Library
  #include <process.h>        // _beginthreadex
  #include <olectl.h>			//CONNECT_E_NOCONNECT
  
  
  ////////////////////////////////////////////////////////////////////////////
  // Globals
  //
  /////////////////////////////////////////////////////////////////////////////
  extern CTable*  g_pTable;						// Global table
  extern CTable*  g_pEmptyTable;					// Empty table
  extern CTable*  g_p1RowTable;					// 1 Row Table
  extern DBCOUNTITEM	g_ulNextRow;				// NextRow
  
  extern IDBInitialize*    g_pIDBInitialize;     //Global DSO ptr
  extern IDBCreateSession* g_pIDBCreateSession;  //Global DSO ptr
  extern IOpenRowset*      g_pIOpenRowset;	   //Global Session ptr
  
  extern CRITICAL_SECTION  GlobalMutex;          //Global Mutex
  
  
  ////////////////////////////////////////////////////////////////////////////
  // Forwards
  //
  /////////////////////////////////////////////////////////////////////////////
  class CStorage;
  class CImpIRowsetNotify;
  class CImpIDBAsynchNotify;
  class CImpIRowPositionChange;
  
  
  ///////////////////////////////////////////////////////////////////////////
  // Provider Specific
  //
  ///////////////////////////////////////////////////////////////////////////
  #define PROVIDER_CLSID GetModInfo()->GetThisTestModule()->m_ProviderClsid
  #define MSDASQL  (CLSID_MSDASQL==PROVIDER_CLSID)
  
  
  ///////////////////////////////////////////////////////////////////////////
  // Strings
  //
  ///////////////////////////////////////////////////////////////////////////
  #define EQUAL_STR 0
  #define ON  TRUE
  #define OFF FALSE
   							  
  
  ///////////////////////////////////////////////////////////////////////////
  // Macros
  // 
  ///////////////////////////////////////////////////////////////////////////
  #define SAFE_RELEASE_DSO(pv)			{ if(pv) ReleaseDataSource((IUnknown**)&(pv)); pv = NULL;	}
  
  #define TCHECK(exp,hr)					CHECK(exp, hr)
  #define TCOMPARE(x,y)					COMPARE(x, y)
  #define TCOMPARE_(x)					COMPARE(x, TRUE)
  
  #define TEST(exp)						{ if(!COMPARE(exp, TRUE)) TRETURN;			}
  #define TEST_(exp,hr)					{ if(!CHECK(exp,hr)) TRETURN;				}
  #define QTEST(exp)						{ if(!QCOMPARE(exp, TRUE)) TRETURN;			}
  #define QTEST_(exp,hr)					{ if(!QCHECK((exp),hr)) TRETURN;			} 
  
  //COMP Macros
  #define COMP(exp1,exp2)					{ if(!COMPARE(exp1,exp2)) TRETURN;			} 
  #define COMPC(exp1,exp2)				{ if(!COMPARE(exp1,exp2)) goto CLEANUP;	} 
  
  //QCOMP Macros
  #define QCOMP(exp1,exp2)				{ if(!QCOMPARE(exp1,exp2)) TRETURN;			} 
  #define QCOMPC(exp1,exp2)				{ if(!QCOMPARE(exp1,exp2)) goto CLEANUP;	} 
  
  #define TEST_PROVIDER(exp)				{ TESTB = TEST_PASS; if(!(exp)) { TOUTPUT_LINE(L"NotSupported by Provider"); TESTB = TEST_SKIPPED; TRETURN; } }
  
  #define MODULENAME						(LPWSTR)gwszModuleName
  
  #define SIZEOF_ONEROW					(sizeof(void*)*m_cRowSize)
  #define SIZEOF_TABLE (5)
  #define MAX_NAME_LEN					 256
  #define MAX_QUERY_LEN					4096
  #define NEGATIVE(ul)					(-(LONG)(ul))
  
  
  
  //////////////////////////////////////////////////////////////////////
  //  Enums
  //
  //////////////////////////////////////////////////////////////////////
  
  //Const int names
  enum {ONE_ROW=1,TWO_ROWS,THREE_ROWS,FOUR_ROWS,FIVE_ROWS,SIX_ROWS,SEVEN_ROWS,EIGHT_ROWS,NINE_ROWS,TEN_ROWS,ELEVEN_ROWS,TWELVE_ROWS,THIRTEEN_ROWS,FOURTEEN_ROWS};
  //Array index names
  enum {ROW_ONE=0,ROW_TWO,ROW_THREE,ROW_FOUR,ROW_FIVE,ROW_SIX,ROW_SEVEN,ROW_EIGHT,ROW_NINE,ROW_TEN,ROW_ELEVEN,ROW_TWELVE,ROW_THIRTEEN,ROW_FOURTEEN};
  //Table index name
  enum {NO_ROWS=0,FIRST_ROW,SECOND_ROW,THIRD_ROW,FOURTH_ROW,FIFTH_ROW,SIXTH_ROW,SEVENTH_ROW,EIGHTH_ROW,NINTH_ROW,TENTH_ROW,TWELTH_ROW,THIRTEENTH_ROW,FOURTEENTH_ROW};
  
  enum {COL_ONE=1};
  
  // Prop status comparison 
  enum VALUE_ENUM
  {
  	NOT_USED=0,			// Ignored
  	VALID_VALUE,		// Value is supported
  	INVALID_VALUE,		// Value is unsupported
  	INDETERMINATE_VALUE	// We don't know whether the value passed is supported
  };
  
  // PropSets comparison 
  enum PROPSETCOMPAREOPTIONS_ENUM
  {
  	EXACT_MATCH=0,				// properties in the properties' sets should exactly match
  	IGNORE_OPTION_FOR_VTEMPTY	// if both properties values are VT_EMPTY then ignore dwOptions mismatch
  };
  
  #define DBPENDINGSTATUS_ALL      ( DBPENDINGSTATUS_NEW |DBPENDINGSTATUS_CHANGED |DBPENDINGSTATUS_DELETED )
  #define DBPART_ALL               ( DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS )
  
  #define DBPROPVAL_NP_ALL         ( DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO	| DBPROPVAL_NP_SYNCHAFTER | DBPROPVAL_NP_FAILEDTODO	| DBPROPVAL_NP_DIDEVENT	)
  #define DBPROPVAL_NP_CANCELABLE  ( DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO	| DBPROPVAL_NP_SYNCHAFTER )
  
  #define DBPROPVAL_UP_ALL         ( DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT )
  
  #define DBPROPVAL_RT_ALL         ( DBPROPVAL_RT_FREETHREAD | DBPROPVAL_RT_APTMTTHREAD | DBPROPVAL_RT_SINGLETHREAD )
  #define DBPROPVAL_RT_BOTH        ( DBPROPVAL_RT_FREETHREAD | DBPROPVAL_RT_APTMTTHREAD )
  
  enum DBASYNCHREASONENUM
  {
  	DBREASON_ONLOWRESOURCE	=	DBREASON_ROW_ASYNCHINSERT	+ 1,
  	DBREASON_ONPROGRESS		=	DBREASON_ONLOWRESOURCE		+ 1,
  	DBREASON_ONSTOP			=	DBREASON_ONPROGRESS			+ 1,
  };
  typedef DWORD DBASYNCHREASON;
  
  
  #define DBREASON_ALL             ( DBREASON_ONSTOP + 1			)
  #define DBEVENTPHASE_ALL         ( DBEVENTPHASE_DIDEVENT + 1	)
  
  
  ////////////////////////////////////////////////////////////////////////
  //  Multi-Threads
  //
  ////////////////////////////////////////////////////////////////////////
  enum {THREAD_ONE=0, THREAD_TWO, THREAD_THREE, THREAD_FOUR, THREAD_FIVE, THREAD_SIX}; 
  enum {ONE_THREAD=1,TWO_THREADS,THREE_THREADS, FOUR_THREADS, FIVE_THREADS, SIX_THREADS, MAX_THREADS=10 };
  
  
  enum {LISTENER_ONE=0, LISTENER_TWO, LISTENER_THREE, LISTENER_FOUR, LISTENER_FIVE}; 
  enum {SOURCE_ONE=0, SOURCE_TWO, SOURCE_THREE, SOURCE_FOUR, SOURCE_FIVE}; 
  
  //This simply the usage of threads down to 3 lines of code, CREATE/START/END
  inline BOOL CreateThreads(LPTHREAD_START_ROUTINE pFunc,void* pArgs,ULONG cThreads,HANDLE* rghThread,DWORD* rgThreadID)
  {
  	ASSERT(pFunc && pArgs && rghThread && rgThreadID);
  
  	for(ULONG i=0; i<cThreads; i++)
  		rghThread[i] = (void*)_beginthreadex(NULL,0,(UINT(WINAPI*)(void*))pFunc,pArgs,CREATE_SUSPENDED,(UINT*)&rgThreadID[i]);
  
  // NOTE: CreateThread (WinAPI) is bad, it doesn't work well with the CrtLib,
  //       Supposed to use, _beginthreadex...  CreateThread is much nicer, and doesn't
  //       require all the "casting", but _begin thread actually delegates out to eventually...
  //		rghThread[i] = CreateThread(NULL,0,pFunc,pArgs,CREATE_SUSPENDED,&rgThreadID[i]);
  
  	return TRUE;
  }
  inline BOOL CreateThread(LPTHREAD_START_ROUTINE pFunc,void* pArg,HANDLE* phThread,DWORD* pThreadID)
  {
  	return CreateThreads(pFunc,pArg,ONE_THREAD,phThread,pThreadID);
  }
  inline BOOL StartThreads(ULONG cThreads, LPHANDLE rghThread)
  {
  	ASSERT(cThreads && rghThread);
  
  	for(ULONG i=0; i<cThreads; i++)
  		ResumeThread(rghThread[i]);
  	return TRUE;
  }
  inline BOOL StartThread(LPHANDLE phThread)
  {
  	return StartThreads(ONE_THREAD,phThread);
  }
  
  extern DWORD WaitForThreads(ULONG cThreads, LPHANDLE rghThread);
  
  inline BOOL EndThreads(ULONG cThreads, LPHANDLE rghThread)
  {
  	WaitForThreads(cThreads, rghThread);
  	for(ULONG i=0; i<cThreads; i++) 
  	   CloseHandle(rghThread[i]);
  	return TRUE;
  }
  inline BOOL EndThread(LPHANDLE phThread)
  {
     return EndThreads(ONE_THREAD,phThread);
  }
  
  inline HRESULT GetThreadCode(HANDLE hThread)
  {
  	HRESULT hr = S_OK;
  
  	//Get the thread return code
  	if(GetExitCodeThread(hThread, (LPDWORD)&hr))
  		return hr;
  
  	DWORD dwLastError = GetLastError();
  	return E_FAIL;
  }
  
  inline BOOL GetThreadResults(ULONG cThreads, HANDLE* rghThreads, HRESULT hrExpected)
  {
  	ULONG cMatched = 0;
  	for(ULONG i=0; i<cThreads; i++)
  	{
  		HRESULT hrActual = GetThreadCode(rghThreads[i]);
  		if(hrActual == hrExpected)
  			cMatched++;
  	}
  
  	return cMatched;
  }
  
  //This simply the usage of threads down to 3 lines of code, CREATE/START/END
  #define INIT_THREADS(cTh)  const ULONG cThreads = cTh; HANDLE rghThread[cThreads]; DWORD rgThreadID[cThreads]
  
  #define CREATE_THREADS(pFunc,pArgs)         CreateThreads(pFunc,pArgs,cThreads,rghThread,rgThreadID)
  #define CREATE_THREAD(iThread,pFunc,pArg)   CreateThreads(pFunc,pArg,ONE_THREAD,&rghThread[iThread],&rgThreadID[iThread])
  
  #define CREATE_FIRST_THREADS(pFunc,pArgs)   CreateThreads(pFunc,pArgs, cThreads/2, rghThread, rgThreadID)
  #define CREATE_SECOND_THREADS(pFunc,pArgs)  CreateThreads(pFunc,pArgs, cThreads-cThreads/2, &rghThread[cThreads/2], &rgThreadID[cThreads/2])
  										   
  #define START_THREADS()                     StartThreads(cThreads,rghThread)     
  #define START_THREAD(iThread)               StartThread(&rghThread[iThread])
  
  #define WAITFOR_THREADS()                   WaitForThreads(cThreads,rghThread)
  #define WAITFOR_THREAD(iThread)             WaitForThreads(1, &rghThread[iThread])
  
  #define END_THREADS()                       EndThreads(cThreads,rghThread)
  #define END_THREAD(iThread)                 EndThread(&rghThread[iThread])
  
  #define GET_THREADRESULTS(hrExpected)			GetThreadResults(cThreads, rghThread, hrExpected)
  #define GET_THREADRESULT(iThread, hrExpected)	GetThreadResults(1, &rghThread[iThread], hrExpected)
  
  
  #define THREAD_FUNC (((THREADARG*)pv)->pFunc)
  #define THREAD_ARG1 ((ULONG_PTR)(((THREADARG*)pv)->pArg1))
  #define THREAD_ARG2 ((ULONG_PTR)(((THREADARG*)pv)->pArg2))
  #define THREAD_ARG4 ((ULONG_PTR)(((THREADARG*)pv)->pArg4))
  #define THREAD_ARG3 ((ULONG_PTR)(((THREADARG*)pv)->pArg3))
  #define THREAD_ARG5 ((ULONG_PTR)(((THREADARG*)pv)->pArg5))
  
  struct THREADARG
  {
  	LPVOID	pFunc;
  	LPVOID	pArg1;
  	LPVOID	pArg2;
  	LPVOID	pArg3;
  	LPVOID	pArg4;
  	LPVOID	pArg5;
  };
  
  inline THREADARG InitThreadArg(void* pFunc, void* pArg1 = NULL, void* pArg2 = NULL, void* pArg3 = NULL, void* pArg4 = NULL, void* pArg5 = NULL)
  {
  	THREADARG ThreadArg = { pFunc, pArg1, pArg2, pArg3, pArg4, pArg5};
  	return ThreadArg;
  }
  
  
  WINOLEAPI  CoInitializeEx(LPVOID pvReserved, DWORD dwCoInit);
  #define THREAD_BEGIN						CoInitializeEx(NULL, 0/*COINIT_MULTITHREADED*/ ); TBEGIN 
  #define	THREAD_BEGIN_(fFreeThreaded)		CoInitializeEx(NULL, fFreeThreaded ? 0/*COINIT_MULTITHREADED*/ : 2/*COINIT_APARTMENTTHREADED*/); TBEGIN 
  #define THREAD_END(hr)						CoUninitialize();		  _endthreadex(hr); return 0;
  #define THREAD_RETURN						CoUninitialize();		  TRETURN
  #define ThreadSwitch()						Sleep(0)
  
  
  ////////////////////////////////////////////////////////////////////////
  // Extern
  //
  ////////////////////////////////////////////////////////////////////////
  extern GUID NULLGUID;
  extern DBID NULLDBID;
  extern DBID INVALID_DBID; 
  extern DBID VALID_INDEXID;
  #define INVALID_TABLEID INVALID_DBID
  #define INVALID_INDEXID INVALID_DBID
  
  
  //////////////////////////////////////////////////////////////////////////////
  //  Memory Alloc/Free Routines
  //
  //  A "safe" wrapper arround CoTaskMemAlloc to protect boundaries
  //////////////////////////////////////////////////////////////////////////////  
  
  #define HEAD_SIGN 0xedededed
  #define TAIL_SIGN 0xdededede
  #define ALLOC_SIGN 0xaa
  #define FREE_SIGN 0xbb
  
  void* BoundarySafeAlloc(ULONG cb); 
  void BoundarySafeFree(void* pv);
  void BoundarySafeFree(ULONG cBuffers, void** ppv);
  
  #define PROVIDER_FREE2(cEle,ppv)	{ if(ppv) for(ULONG i=0; i<cEle; i++) PROVIDER_FREE(ppv[i]); /*ppv = NULL;*/ }
  
  
  ////////////////////////////////////////////////////////////////////
  // General Misc Helper Functions
  //
  ////////////////////////////////////////////////////////////////////
  
  BOOL CreateTable(CTable** ppTable, DBCOUNTITEM cRows);
  BOOL DropTable(CTable** ppTable);
  HRESULT TableInsert(DBCOUNTITEM cRows, CTable* pCTable = g_pTable);
  
  BOOL VerifyOutputInterface(HRESULT hr, REFIID riid, IUnknown** ppIUnknown);
  BOOL ValidInterface(IID riid, IUnknown* pIUnknown);
  BOOL SupportedInterface(IID riid, EINTERFACE eInterface = UNKNOWN_INTERFACE);
  BOOL VerifyThreadingModel(CLSID clsidProv, WCHAR* pwszThreadingModel, CLSCTX clsctx = CLSCTX_INPROC_SERVER);
  
  BOOL CommonModuleInit(CThisTestModule * pThisTestModule, REFIID riid = IID_IUnknown, DBCOUNTITEM cRows = SIZEOF_TABLE, EINTERFACE eInterface = UNKNOWN_INTERFACE);
  BOOL CommonModuleTerminate(CThisTestModule * pThisTestModule); 
  
  #define PERSIST_FILE L"Persist.sav"
  HRESULT SaveDSO(WCHAR* pwszFileName);
  
  HRESULT CreateNewDSO(IUnknown* pIUnkOuter, REFIID riid, IUnknown** ppIUnknown, DWORD dwOptions = CREATEDSO_SETPROPERTIES | CREATEDSO_INITIALIZE);
  
  BOOL	ShouldInitialize(IUnknown* pDataSource);
  HRESULT InitializeDataSource(IUnknown* pDataSource, DWORD dwOptions = CREATEDSO_SETPROPERTIES | CREATEDSO_INITIALIZE);
  HRESULT ReleaseDataSource(IUnknown** ppDataSource);
  HRESULT CreateNewSession(IUnknown* pIDataSource, REFIID riid, IUnknown** ppIUnknown, IUnknown* pIUnkOuter = NULL);
  HRESULT CreateNewCommand(IUnknown* pISession, REFIID riid, IUnknown** ppIUnknown, IUnknown* pIUnkOuter = NULL);
  
  BOOL CanConvert(IUnknown* pIUnknown, DBTYPE wFromType, DBTYPE wToType);
  HRESULT	ConvertString(WCHAR* pwszBuffer, BOOL fUpperCase = TRUE);
  WCHAR*	CreateString(WCHAR* pwszFmt, ...);
  HRESULT	AppendString(WCHAR** ppwszOldString, WCHAR* pwszAppend);
  BOOL GetTableSchemaInfo(CTable* pTable,	WCHAR* pwszTargetTable,	BOOL* pfFound, WCHAR** ppwszCatalogName = NULL, WCHAR** ppwszSchemaName = NULL);
  BOOL FreeAccessorBufferAndBindings(DBCOUNTITEM *pcBindings, DBBINDING **prgBindings, void **ppData, bool bFreeBuffer = false);
  
  ////////////////////////////////////////////////////////////////////////////
  // Window functions
  //
  ////////////////////////////////////////////////////////////////////////////
  BOOL		IsUnicodeOS();
  
  
  ///////////////////////////////////////////////////////////////
  // Registry
  //
  ///////////////////////////////////////////////////////////////
  HRESULT		CreateRegKey(HKEY hRootKey, WCHAR* pwszKeyName, HKEY* phKey, REGSAM samDesired = KEY_READ | KEY_WRITE);
  HRESULT		OpenRegKey(HKEY hRootKey, WCHAR* pwszKeyName, DWORD ulOptions, REGSAM samDesired, HKEY* phKey);
  
  HRESULT		GetRegEnumKey(HKEY hRootKey, WCHAR* pwszKeyName, DWORD dwIndex, WCHAR* pwszSubKeyName, ULONG cBytes);
  HRESULT		GetRegEnumValue(HKEY hRootKey, WCHAR* pwszKeyName, DWORD dwIndex, WCHAR** ppwszValueName);
  HRESULT		GetRegEnumValue(HKEY hRootKey, WCHAR* pwszKeyName, DWORD dwIndex, WCHAR* pwszValueName, ULONG* pcBytes);
  
  HRESULT		GetRegEntry(HKEY hRootKey, WCHAR* pwszKeyName, WCHAR* pwszValueName, WCHAR* pwszValue, ULONG cBytes);
  HRESULT		GetRegEntry(HKEY hRootKey, WCHAR* pwszKeyName, WCHAR* pwszValueName, ULONG* pulValue);
  HRESULT		GetRegEntry(HKEY hRootKey, WCHAR* pwszKeyName, WCHAR* pwszValueName, void* pStruct, ULONG cbSize, ULONG dwType = REG_BINARY);
  
  HRESULT		SetRegEntry(HKEY hRootKey, WCHAR* pwszKeyName, WCHAR* pwszValueName, WCHAR* pwszValue);
  HRESULT		SetRegEntry(HKEY hRootKey, WCHAR* pwszKeyName, WCHAR* pwszValueName, ULONG ulValue);
  HRESULT		SetRegEntry(HKEY hRootKey, WCHAR* pwszKeyName, WCHAR* pwszValueName, void* pStruct, ULONG cbSize, ULONG dwType = REG_BINARY);
  
  HRESULT		DelRegEntry(HKEY hRootKey, WCHAR* pwszKeyName);
  HRESULT		DelAllRegEntry(HKEY hRootKey, WCHAR* pwszKeyName);
  
  HRESULT		CloseRegKey(HKEY hKey);
  
  
  
  ///////////////////////////////////////////////////////////////////
  // Storage Object helpers
  //
  ///////////////////////////////////////////////////////////////////
  
  DBBINDING* FindBinding(DBCOUNTITEM cBindings, DBBINDING* rgBindings, DBTYPE wType, DBCOUNTITEM* pulIndex = NULL);
  BOOL GetStorageObject(    DBCOUNTITEM cBindings, DBBINDING* rgBindings, void* pData, REFIID riid, IUnknown** ppIUnknown);
  BOOL SetStorageObject(    DBCOUNTITEM cBindings, DBBINDING* rgBindings, void* pData, DBCOUNTITEM iTableRow = 0, REFIID riid = IID_IUnknown, CStorage* pCStorage = NULL, DBSTATUS dbStatus = DBSTATUS_S_OK, DBLENGTH cBytes = MAX_PTR);
  
  HRESULT GetStorageData(DBCOUNTITEM cBindings, DBBINDING* rgBindings, void* pData, void* pBuffer, ULONG* pcBytes = NULL, REFIID riid = IID_IUnknown, IUnknown** ppIUnknown = NULL);
  HRESULT GetStorageData(REFIID riid, IUnknown* pIUnknown, void* pBuffer, ULONG* pcBytes = NULL);
  BOOL CreateData(void** ppBuffer, DBCOUNTITEM iTableRow, DBBINDING* pBindings, DBLENGTH* pcSize);
  
  BOOL VerifyAccessorStatus(DBCOUNTITEM cBindings, DBBINDING* rgBindings, DBBINDSTATUS* rgBindStatus, DBTYPE wType, DBBINDSTATUS dwBindStatus);
  BOOL VerifyBindingStatus(DBCOUNTITEM cBindings, DBBINDING* rgBindings, void* pData, DBTYPE wType, DBSTATUS dwStatus);
  BOOL VerifyBindings(HRESULT hrReturned, IAccessor* pIAccessor, HACCESSOR hAccessor, void* pData);
  
  
  ////////////////////////////////////////////////////////////////////
  // Property Routines
  //
  ////////////////////////////////////////////////////////////////////
  VARTYPE GetPropInfoType(DBPROPID dwPropertyID, GUID guidPropertySet);
  DBPROPFLAGS GetPropInfoFlags(DBPROPID dwPropertyID, GUID guidPropertySet);
  DBPROPINFO* GetPropInfo(DBPROPID dwPropertyID, GUID guidPropertySet);
  WCHAR* GetPropDesc(DBPROPID dwPropertyID, GUID guidPropertySet, IUnknown* pDataSource = NULL);
  
  BOOL FindPropSet(GUID guidPropertySet, ULONG cPropSets, DBPROPSET* rgPropSets, DBPROPSET** ppPropSet = NULL);
  BOOL FindProperty(DBPROPID dwPropertyID, GUID guidPropertySet, ULONG cPropSets, DBPROPSET* rgPropSets, DBPROP** ppProp = NULL);
  BOOL EqualProperty(DBPROP* pProp, DBPROP* pProp2, enum PROPSETCOMPAREOPTIONS_ENUM eCompareOptions = EXACT_MATCH);
  BOOL EqualPropSets(ULONG cPropSets, DBPROPSET* rgPropSets, ULONG cPropSets2, DBPROPSET* rgPropSets2, enum PROPSETCOMPAREOPTIONS_ENUM eCompareOptions = EXACT_MATCH);
  
  BOOL SupportedProperty(DBPROPID dwPropertyID, GUID guidPropertySet);
  BOOL SettableProperty(DBPROPID dwPropertyID, GUID guidPropertySet);
  
  BOOL SetSupportedProperty(DBPROPID dwPropertyID, GUID guidPropertySet, ULONG* pcPropSets, DBPROPSET** prgPropSets, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  BOOL SetSettableProperty(DBPROPID dwPropertyID, GUID guidPropertySet, ULONG* pcPropSets, DBPROPSET** prgPropSets, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  BOOL SetProperty(DBPROPID dwPropertyID, GUID guidPropertySet, ULONG* pcPropIDSets, DBPROPIDSET** prgPropIDSets);
  BOOL SetProperty(DBPROPID dwPropertyID, GUID guidPropertySet, ULONG* pcPropSets, DBPROPSET** prgPropSets, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  
  BOOL GetPropStatus(ULONG cPropSets, DBPROPSET* rgPropSets, DBPROPID dwPropertyID, GUID guidPropertySet, DBPROPSTATUS* pdwInputStatus);
  BOOL VerifyPropSetStatus(ULONG cPropSets, DBPROPSET* rgPropSets, DBPROPSTATUS dwPropStatus = DBPROPSTATUS_OK);
  BOOL VerifyPropStatus(ULONG cPropSets, DBPROPSET* rgPropSets, ULONG dwProperty, GUID guidPropertySet, DBPROPSTATUS dwPropStatus = DBPROPSTATUS_OK, enum VALUE_ENUM eValue = NOT_USED);
  
  BOOL FreePropInfos(ULONG cPropertyInfos, DBPROPINFO* rgPropInfos);
  BOOL FindValue(DBCOUNTITEM ulValue, DBCOUNTITEM cElements, DBCOUNTITEM* rgElements);
  
  
  
  ////////////////////////////////////////////////////////////////////
  // Notifications
  //
  ////////////////////////////////////////////////////////////////////
  WCHAR* GetPhaseDesc(DBEVENTPHASE ePhase);
  WCHAR* GetReasonDesc(DBREASON eReason);
  WCHAR* GetAsynchPhase(DBASYNCHPHASE ePhase);
  
  
  ////////////////////////////////////////////////////////////////////
  // inline Misc Helpfer Functions
  //
  ////////////////////////////////////////////////////////////////////
  HRESULT QI(IUnknown* pExistingIUnknown,REFIID riid,void** ppRequestedIUnknown = NULL);
  BOOL	VerifyArray(DBCOUNTITEM cEle, ULONG* rgEle, ULONG scode);
  
  inline BOOL Prepare(ICommand* pICommand)
  {
  	ASSERT(pICommand);
  	
  	TBEGIN
      ICommandPrepare* pICommandPrepare = NULL;
  
      //Obtain the prepare interface
  	TESTC_(QI(pICommand, IID_ICommandPrepare, (void**)&pICommandPrepare),S_OK)
  
  	//prepare the command
  	TESTC_(pICommandPrepare->Prepare(0),S_OK)
  
  CLEANUP:
  	SAFE_RELEASE(pICommandPrepare);
  	TRETURN
  }
  
  //////////////////////////////////////////////////////////////////////////////
  //  BitWise manipulations
  //
  //////////////////////////////////////////////////////////////////////////////
  inline ULONG EnumToBitmask(ULONG eValue)  
  {
  	ULONG ulMask = 0x1;
  
  	//Has to be less then the numer of "bits" in the return value
  	ASSERT(eValue < (sizeof(ULONG)*8)); 
  	return ulMask << (eValue);
  }
  #define BITSET(val, mask)   (((val) & (mask)) == (mask))
  #define BITCLEAR(val, mask) (!((val) & (mask)))
  
  #define SETBIT(val, mask)   ((val) |= (mask))
  #define CLEARBIT(val, mask) ((val) &= ~(mask))
  
  
  
  /////////////////////////////////////////////////////////////////////////////
  // Enumerator Operations
  //
  /////////////////////////////////////////////////////////////////////////////
  struct ENUMINFO
  {
  	WCHAR			wszName[MAX_NAME_LEN];
  	WCHAR			wszParseName[MAX_NAME_LEN];
  	WCHAR			wszDescription[MAX_NAME_LEN];
  	DBTYPE			wType;
  	VARIANT_BOOL	fIsParent;
  };
  
  HRESULT GetEnumInfo(IParseDisplayName* pIParseDisplayName, ULONG* pcEnumInfo, ENUMINFO** prgEnumInfo);
  HRESULT CreateFromDisplayName(IParseDisplayName* pIParseDisplayName, WCHAR* pwszDisplayName, REFIID riid, IUnknown** ppIUnknown);
  
  
  //////////////////////////////////////////////////////////////////////////
  // Class CDataSource
  //
  // Basically a nice wrapper arround a DataSource object.  
  //////////////////////////////////////////////////////////////////////////
  class CDataSource : public CDataSourceObject
  {
  public:
  	//Constructors
  	CDataSource(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
      virtual ~CDataSource();
  
      //members
  	virtual BOOL Init();
  	virtual BOOL Terminate();
  
      //cast operator
  	virtual IDBInitialize*  const pIDBInit();
  	virtual IUnknown*		const pDataSource();
  	virtual IDBInitialize*  const operator ()();
  		
      virtual HRESULT CreateInstance();
      virtual HRESULT Initialize(IUnknown* pDataSource, EREINITIALIZE eReinitialize = REINITIALIZE_YES);
      virtual HRESULT Initialize(EREINITIALIZE eReinitialize = REINITIALIZE_YES);
      virtual HRESULT Uninitialize();
  
  	//GetProperties
  	virtual HRESULT GetPropertyInfo(GUID guidPropertySet, ULONG* pcPropInfoSets = NULL, DBPROPINFOSET** prgPropInfoSets = NULL, WCHAR** ppwszStringBuffer = NULL);
  
  	//SetProperties
      virtual BOOL SetProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
      virtual BOOL SetSupportedProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
      virtual BOOL SetSettableProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  	virtual BOOL FreeProperties();
  
  	//Verification
  	virtual BOOL	VerifyDataSource(IUnknown* pDataSource, REFCLSID rclsid);
  	virtual BOOL	VerifyDataSource(IUnknown* pDataSource, DBPROPID dwPropertyID, GUID guidPropertySet, DBTYPE wType, void* pValue);
  	
  
      //data 
  	ULONG	    m_cPropSets;
  	DBPROPSET*  m_rgPropSets;
  };
  
  
  //////////////////////////////////////////////////////////////////
  // Class COpenRowset
  //
  // Used to create multiple instantes of CTestCases even though our
  // privlib is really not designed for it, quite a useful hack...
  //////////////////////////////////////////////////////////////////
  
  class COpenRowset : public CSessionObject
  {
  public:
  	//Constructors
  	COpenRowset(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
  	virtual ~COpenRowset();
  
      //methods
      virtual BOOL Init();
      virtual BOOL Terminate();
  
      //helper
      virtual HRESULT CreateOpenRowset(IID riid = IID_IRowset, IUnknown** ppIRowset = NULL, IUnknown* pIUnkOuter = NULL, EINTERFACE eInterface = ROWSET_INTERFACE);
      virtual HRESULT CreateOpenRowset(CTable* pCTable,IID riid = IID_IRowset, IUnknown** ppIRowset = NULL, IUnknown* pIUnkOuter = NULL, EINTERFACE eInterface = ROWSET_INTERFACE);
  
      virtual BOOL SetProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
      virtual BOOL SetSupportedProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
      virtual BOOL SetSettableProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  	virtual BOOL FreeProperties();
  	
      //interface
  	virtual IUnknown*	const pISession();
      virtual IOpenRowset* const operator()();
      virtual IOpenRowset* const pIOpenRowset();
  
  //protected:
      //data 
  	ULONG	    m_cPropSets;
  	DBPROPSET*  m_rgPropSets;
      
  protected:
      //data pointers
  };
  
  
  //////////////////////////////////////////////////////////////////////////
  // Class CCommand
  //
  // Basically a nice wrapper arround a command object.  
  //////////////////////////////////////////////////////////////////////////
  class CCommand : public CCommandObject
  {
  public:
  	//Constructors
  	CCommand(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
      virtual ~CCommand();
  
      //members
  	virtual BOOL		Init();
  	virtual BOOL		Terminate();
  
  	//Helpers
  	virtual HRESULT		CreateCommand(IUnknown* pIUnkOuter = NULL);
  	virtual HRESULT		SetCommandText(EQUERY eQuery, REFGUID rguidDialect = DBGUID_DEFAULT);
  	virtual HRESULT		SetProperties();
  	virtual HRESULT		Execute(IUnknown* pUnkOuter, REFIID riid, IUnknown** ppRowset, DBROWCOUNT* pcRowsAffected = NULL, DBPARAMS* pParams = NULL);
  
  	virtual BOOL		SetProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  	virtual BOOL		FreeProperties();
  
  //protected:
  	ICommandText*		m_pICommandText;
  	ICommandProperties*	m_pICommandProperties;
  
  	ULONG				m_cPropSets;
  	DBPROPSET*			m_rgPropSets;
  };
  
  
  //////////////////////////////////////////////////////////////////////////
  // Class CRowset
  //
  // Basically a nice wrapper arround a rowset object.  This test will use
  // multiple rowsets, and its easier to have all the general functionality
  // together
  //////////////////////////////////////////////////////////////////////////
  
  class CRowset : public CRowsetObject
  {
  public:
  	//Constructors
  	CRowset(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
      virtual ~CRowset();
  
      //members
  	virtual BOOL Init();
  	virtual BOOL Terminate();
  
  	virtual HRESULT CreateCommand(EQUERY eQuery = USE_SUPPORTED_SELECT_ALLFROMTBL);
  	virtual HRESULT CreateAccessor(HACCESSOR* phAccessor, DBACCESSORFLAGS dwAccessorFlags, DBPART dwPart = DBPART_ALL, DBCOUNTITEM* pcBindings=NULL, DBBINDING** prgDBBINDING=NULL, DBLENGTH* pcRowSize=NULL, BLOBTYPE dwBlobType = NO_BLOB_COLS, DBBINDSTATUS** prgBindStauts = NULL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLS_BY_REF eColsByRef = NO_COLS_BY_REF, DBTYPE dwModifier = DBTYPE_EMPTY);
  
      virtual HRESULT CreateRowset(EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
      virtual HRESULT CreateRowset(DBPROPID dwProperty, EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
  	virtual HRESULT CreateRowset(IUnknown* pIRowset, EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
  
  	virtual HRESULT CreateRowsetFromTbl(DBCOUNTITEM cTableSize);
  	virtual HRESULT	DropRowset();
  
  	//helpers
  	virtual BOOL SetProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
      virtual BOOL SetSupportedProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
      virtual BOOL SetSettableProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, void* pValue = (void*)VARIANT_TRUE, DBTYPE wType = DBTYPE_BOOL, DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED, DBID colid = DB_NULLID);
  
  	virtual BOOL GetProperty(DBPROPID dwPropertyID, GUID guidPropertySet = DBPROPSET_ROWSET, VARIANT_BOOL bValue = VARIANT_TRUE);
  	virtual BOOL GetProperty(DBPROPID dwPropertyID, GUID guidPropertySet, VARIANT_BOOL* pbValue);		 
  	virtual BOOL GetProperty(DBPROPID dwPropertyID, GUID guidPropertySet, ULONG_PTR* pulValue);		 
  	virtual BOOL GetProperty(DBPROPID dwPropertyID, GUID guidPropertySet, WCHAR** ppwszValue);		 
  	virtual BOOL FreeProperties();
  
  	//Wrappers
  	virtual HRESULT GetRow(DBCOUNTITEM iRow, HROW* phRow);
  	virtual HRESULT GetRow(DBCOUNTITEM iRow, DBCOUNTITEM cRows, HROW* rghRow);
  	virtual HRESULT GetRow(DBCOUNTITEM iRow, DBCOUNTITEM cRows, DBCOUNTITEM* pcRowsObtained, HROW* rghRow);
  
  	virtual HRESULT GetNextRows(HROW* phRow);
  	virtual HRESULT GetNextRows(DBROWCOUNT cRows, HROW* rghRow);
  	virtual HRESULT GetNextRows(DBROWOFFSET lOffset, DBROWCOUNT cRows, HROW* rghRow);
  	virtual HRESULT GetNextRows(DBROWOFFSET lOffset, DBROWCOUNT cRows, DBCOUNTITEM* pcRowsObtained, HROW* rghRow);
  	virtual HRESULT GetNextRows(DBROWOFFSET lOffset, DBROWCOUNT cRows, DBCOUNTITEM* pcRowsObtained, HROW** rghRow);
  
  	virtual HRESULT ReleaseRows(HROW hRow);
  	virtual HRESULT ReleaseRows(DBCOUNTITEM cRows, HROW* rghRow, DBREFCOUNT* rgRefCounts, DBROWSTATUS* rgRowStatus = NULL);
  	virtual HRESULT ReleaseRows(DBCOUNTITEM cRows, HROW* rghRow, DBREFCOUNT** prgRefCounts = NULL, DBROWSTATUS** prgRowStatus = NULL);
  
  	virtual HRESULT ReleaseAccessor(HACCESSOR hAccessor, DBCOUNTITEM cBindings = 0, DBBINDING* rgBindings = NULL, void* pData = NULL);
  	virtual HRESULT RestartPosition(HCHAPTER hChapter = DB_INVALID_HCHAPTER);
  
  	virtual HRESULT GetRowData(HROW hRow, void** ppData);
  	virtual HRESULT GetRowData(DBCOUNTITEM cRows, HROW* rghRow, void** ppData);
  	virtual HRESULT GetData(HROW hRow, HACCESSOR hAccessor, void* pData);
  
  	virtual DBCOUNTITEM   GetTotalRows();
      virtual DBORDINAL   GetTotalColumns(BOOL fIncludeBookmark = FALSE);
  	
  	virtual HRESULT FindColInfo(DBCOLUMNFLAGS dwFlags, DBCOLUMNINFO* pColInfo);
  	virtual HRESULT GetColInfo(DBORDINAL* pcColumns, DBCOLUMNINFO** prgInfo, WCHAR** ppStringsBuffer=NULL);
  	virtual HRESULT GetBookmark(HROW hRow, DBBKMARK *pcbBookmark, BYTE **ppBookmark);
  
  	virtual HRESULT ResynchRows(DBCOUNTITEM cRows,HROW* rghRow,DBCOUNTITEM* pcResynchedRows = NULL, HROW** prgResynchedRows = NULL, DBROWSTATUS** prgRowStatus = NULL);
  
  	//IGetRow
  	virtual HRESULT GetRowObject(DBCOUNTITEM iRow, CRowObject* pCRowObject, ULONG_PTR ulpOleObjects = 0, HROW hRowSpecified = NULL);
  	virtual HRESULT GetRowObject(IUnknown* pIUnkOuter, DBCOUNTITEM iRow, REFIID riid, IUnknown** ppIUnknown, ULONG_PTR ulpOleObjects = 0, HROW hRowSpecified = NULL);
  	virtual HRESULT GetRowFromHROW(IUnknown* pIUnkOuter, HROW hRow, REFIID riid, IUnknown** ppIUnknown);
  	virtual HRESULT GetURLFromHROW(HROW hRow, WCHAR** ppwszURL);
  
  	//helpers
  	virtual BOOL CompareRowData(void* pOrgData, void* pData, HACCESSOR hAccessor = DB_NULL_HACCESSOR, BOOL fSetData = FALSE);
  	virtual BOOL CompareRowData(HROW hRow, void* pData);
  	virtual BOOL CompareRowData(DBCOUNTITEM cRows, HROW* rghRow, void** rgpData);
  
  	virtual HRESULT GetStorageData(HROW hRow, HACCESSOR hAccessor, void* pBuffer = NULL, ULONG* pcBytes = NULL, REFIID riid = IID_IUnknown, IUnknown** ppIUnknown = NULL);
  
      virtual BOOL VerifyRowHandles(DBCOUNTITEM iRow, HROW hRow);
  	virtual BOOL VerifyRowHandles(DBCOUNTITEM cRows, HROW* rghRows, DBCOUNTITEM	iRowStart, ECOLUMNORDER eOrder = FORWARD);
  	virtual BOOL CompareTableData(DBCOUNTITEM iTableRow, void* pData, DBCOUNTITEM cBindings = 0, DBBINDING* rgBindings = NULL);
  
      virtual BOOL VerifyAllRows();
      virtual BOOL CompareRowset(IUnknown* pIRowset);
  
  	virtual BOOL ValidRow(HROW hRow);
  	virtual BOOL ValidRow(DBCOUNTITEM cRows, HROW* rghRow);
  	virtual BOOL IsSameRow(HROW hRow1, HROW hRow2);
  
  	//Create Data
  	virtual BOOL MakeRowData(void** ppData, HACCESSOR hAccessor = DB_NULL_HACCESSOR, DBCOUNTITEM* piRow = NULL);
  	virtual BOOL ReleaseRowData(void* pData, HACCESSOR hAccessor = DB_NULL_HACCESSOR, BOOL fFreeBuffer = TRUE);
  
      //cast operator
  	virtual IUnknown*	const pISession();
  	virtual IAccessor*	const pIAccessor();
  	virtual ICommand*	const pICommand();
  	virtual IUnknown*	const pIUnknown();
  	virtual IRowset*	const pIRowset();
  	virtual IRowset*	const operator ()();
  
  	virtual CTable* const pTable();
  	virtual DBCOUNTITEM   GetMaxOpenRows() { return m_ulMaxOpenRows; }
  	virtual BOOL    AllowOpenRows(DBCOUNTITEM cOpenRows) { return m_ulMaxOpenRows==0 || m_ulMaxOpenRows>=cOpenRows; }
  		
  	//data
  	HACCESSOR			m_hAccessor;
  	DBLENGTH			m_cRowSize;
  	DBCOUNTITEM			m_cBindings;
  	DBBINDING*			m_rgBinding;
  	void*				m_pData;
  
  	DBCOUNTITEM			m_ulTableRows;
  	DBCOUNTITEM			m_ulMaxOpenRows;
  	BOOL				m_bCanHoldRows;
  	BOOL				m_bCanFetchBackwards;
  	BOOL				m_bCanScrollBackwards;
  	ULONG_PTR			m_ulpOleObjects;
  
  protected:
  	//data pointers
  	IUnknown*		   m_pIUnknown;
  	IRowset*		   m_pIRowset;
  };
  
  
  ////////////////////////////////////////////////////////////////////
  // Class CRowsetChange
  //
  // Conatins all the functionality of IRowsetChange as well as all the
  // IRowset functionality
  ////////////////////////////////////////////////////////////////////
  
  class CRowsetChange : public CRowset
  {
  public:
  	//contsructor
  	CRowsetChange(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
      virtual ~CRowsetChange();
  	virtual BOOL Terminate();
  
  	// SetData methods
  	virtual HRESULT ModifyRow(HROW hRow);
  	virtual HRESULT ModifyRow(DBCOUNTITEM cRows, HROW* rghRow);
  	virtual HRESULT SetData(HROW hRow, HACCESSOR hAccessor, void* pData);
  
  	// Delete mothods
  	virtual HRESULT DeleteRow(HROW hRow);
  	virtual HRESULT DeleteRow(DBCOUNTITEM cRows, HROW* rghRow, DBROWSTATUS* rgRowStatus = NULL);
  
  	// InsertRow methods
  	virtual HRESULT InsertRow(HROW* phRow);
      virtual HRESULT InsertRow(DBCOUNTITEM cRows, HROW* rghRow);
  	virtual HRESULT InsertRow(HACCESSOR hAccessor, void* pData, HROW* phRow);
  
      virtual HRESULT CreateRowset(EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
      virtual HRESULT CreateRowset(DBPROPID dwProperty, EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
      virtual HRESULT CreateRowset(IUnknown* pIRowset, EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
  
  	//Interface to private members
  	virtual IRowsetChange* const pIRowsetChange();
  	
  protected:
  	//Data
  	IRowsetChange*				m_pIRowsetChange;  
  };
  //////////////////////////////////////////////////////////////////
  // Class CRowsetUpdate
  //
  // Conatins all the functionality of IRowsetUpdate as well as the
  // ability of CRowsetChange
  //////////////////////////////////////////////////////////////////
  
  
  class CRowsetUpdate : public CRowsetChange
  {
  public:
  	//contsructor
  	CRowsetUpdate(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
      virtual ~CRowsetUpdate();
  	virtual BOOL Terminate();
  
  	//Wrappers
  	virtual HRESULT HardDeleteRow(HROW hRow);
  	virtual HRESULT HardDeleteRow(DBCOUNTITEM cRows, HROW* rghRow);
  
  	//IRowsetUpdate::Update
  	virtual HRESULT UpdateRow(HROW hRow);
  	virtual HRESULT UpdateRow(DBCOUNTITEM cRows, HROW* rghRow, DBCOUNTITEM* pcUpdatedRows = NULL, HROW** prgUpdatedRows = NULL, DBROWSTATUS** prgRowStatus = NULL);
  	virtual HRESULT UpdateAll();
  	
  	//IRowsetUpdate::Undo
  	virtual HRESULT UndoRow(HROW hRow);
  	virtual HRESULT UndoRow(DBCOUNTITEM cRows,HROW* rghRow,DBCOUNTITEM* pcRowsUndone = NULL, HROW** prgRowsUndone = NULL, DBROWSTATUS** prgRowStatus = NULL);
  	virtual HRESULT UndoAll();
  	
  	//IRowsetUpdate::GetPendingRows
  	virtual HRESULT GetPendingRows(DBCOUNTITEM PendingRows);
  	virtual HRESULT GetPendingRows(DBPENDINGSTATUS RowStatus, DBCOUNTITEM PendingRows);
  	virtual HRESULT GetPendingRows(DBPENDINGSTATUS RowStatus, DBCOUNTITEM PendingRows, DBPENDINGSTATUS PendingStatus);
  	
  	//IRowsetUpdate::GetOriginalData
  	virtual HRESULT GetOriginalData(HROW hRow, void** ppData);
  	virtual HRESULT GetOriginalData(DBCOUNTITEM cRows, HROW* rghRow, void** ppData);
  
  	//IRowsetUpdate::GetRowStatus
  	virtual HRESULT GetRowStatus(HROW hRow, DBROWSTATUS RowStatus);
  	virtual HRESULT GetRowStatus(DBCOUNTITEM cRows , HROW* rghRow, DBROWSTATUS RowStatus);
  
  	//helpers
  	virtual BOOL CompareOrgRowData(HROW hRow);
  	
  	virtual BOOL CompareOrgStorageData(HROW hRow, HACCESSOR hAccessor, void* pBuffer);
  	virtual HRESULT GetOrgStorageData(HROW hRow, HACCESSOR hAccessor, void* pBuffer = NULL, ULONG* pcBytes = NULL, REFIID riid = IID_IUnknown, IUnknown** ppIUnknown = NULL);	
  	
  	virtual BOOL CompareWithDefaults(void* pData);
  
      virtual HRESULT CreateRowset(EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
      virtual HRESULT CreateRowset(DBPROPID dwProperty, EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
      virtual HRESULT CreateRowset(IUnknown* pIRowset, EQUERY eQuery = SELECT_ORDERBYNUMERIC, REFIID riid = IID_IRowset, CTable* pCTable = NULL, DBACCESSORFLAGS dwAccessorFlags = DBACCESSOR_ROWDATA, DBPART dwPart = DBPART_ALL, DWORD dwColsBound = UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder = FORWARD, ECOLS_BY_REF	eColsByRef = NO_COLS_BY_REF, DBTYPE	wTypeModifier = DBTYPE_EMPTY, BLOBTYPE dwBlobType = NO_BLOB_COLS);
  	
  	//Interface to private methods, can't modify
  	virtual IRowsetUpdate* const pIRowsetUpdate();
  	virtual DBCOUNTITEM   GetMaxPendingRows() { return m_ulMaxPendingRows; }
  	virtual BOOL    AllowPendingRows(DBCOUNTITEM cPendingRows) { return m_ulMaxPendingRows==0 || m_ulMaxPendingRows>=cPendingRows; }
  
  protected:
  	//Data
  	IRowsetUpdate*				m_pIRowsetUpdate;
  	DBCOUNTITEM						m_ulMaxPendingRows;
  };
  
  
  ///////////////////////////////////////////////////////////////////////////////
  // Class CListener
  // 
  // Listens on the connections for notifications, (ie: a sink)
  //////////////////////////////////////////////////////////////////////////////
  class CListener : public CBase
  {
  public:
  	CListener(REFIID riid = IID_IUnknown, IUnknown* pIUnknown = NULL);
  	virtual ~CListener();
  
  	//IUnknown
  	DEFINE_QI_ADDREF_RELEASE;
  
  	//Helpers
  	virtual HRESULT Advise(DWORD* pdwCookie, IUnknown* pIUnknown = NULL, REFIID riid = IID_IUnknown);
  	virtual HRESULT Unadvise(DWORD dwCookie, IUnknown* pIUnknown = NULL, REFIID riid = IID_IUnknown);
  
  	virtual BOOL	SetNotifications(BOOL bValue = TRUE)				{	m_bFire = bValue;	return TRUE; }
  	virtual BOOL	SetCancel(DBREASON eReason, DBEVENTPHASE ePhase)	{ 	m_eCancelReason = eReason;	m_eCancelPhase = ePhase; return TRUE; }
  	virtual BOOL	SetError(HRESULT hr)								{	m_hrReturn = hr; return TRUE; }
  	virtual BOOL	SetType(REFIID riid = IID_IUnknown)					{	m_iid = riid; return TRUE; }
  
  	virtual BOOL	WantedEvent(DBREASON eReason, DBEVENTPHASE ePhase);
  	virtual BOOL	SetEvent(DBREASON eReason, DBEVENTPHASE ePhase, BOOL bValue = TRUE);
  
  	virtual BOOL	SetAdvise(DBREASON eReason, DBEVENTPHASE ePhase)	{	m_eAdviseReason	= eReason;	m_eAdvisePhase	= ePhase;	return TRUE; }	
  	virtual BOOL	SetUnadvise(DBREASON eReason, DBEVENTPHASE ePhase)	{	m_eUnadviseReason = eReason; m_eUnadvisePhase = ePhase;	 return TRUE; }
  
  	virtual BOOL	Restart();
  	virtual BOOL	ResetTimesNotified(DBREASON eReason = DBREASON_ALL, DBEVENTPHASE ePhase = DBEVENTPHASE_ALL);
  	virtual ULONG	GetTimesNotified(DBREASON eReason = DBREASON_ALL, DBEVENTPHASE ePhase = DBEVENTPHASE_ALL);
  	virtual BOOL	IsCancelable(DBREASON eReason, DBEVENTPHASE ePhase, IUnknown* pIUnknown = NULL);
  	virtual HRESULT	CauseNotification(DBREASON eReason, IUnknown* pIUnknown = NULL);
  
  	virtual BOOL	SetReEntrantcy(DBREASON eReason, DBEVENTPHASE ePhase, void* pReEntrantFunc, void* pReEntrantData);
  	virtual BOOL	GetReEntrantcy(DBREASON eReason, DBEVENTPHASE ePhase, void** ppReEntrantFunc, void** ppReEntrantData);
  
  	//Helpers
  	virtual HRESULT AcceptOrVeto(
  						IUnknown*		pIUnknown,
  						DBREASON		eReason,		// @parm IN	| Reason for notification
  						DBEVENTPHASE	ePhase, 		// @parm IN	| Phase of event
  						BOOL            fCantDeny);
  
  protected:
  	//Data
  	//OPTIONAL
  	CImpIRowsetNotify*				m_pCImpIRowsetNotify;
  	CImpIDBAsynchNotify*			m_pCImpIDBAsynchNotify;
  	CImpIRowPositionChange*			m_pCImpIRowPositionChange;
  
  	DBREASON		m_eCancelReason;  // Weither to Cancel/Veto the notifcation
  	DBEVENTPHASE	m_eCancelPhase;   // Weither to Cancel/Veto the notifcation
  
  	DBREASON		m_eAdviseReason;	//Reason to advise another listener on
  	DBEVENTPHASE	m_eAdvisePhase;		//Phase to advise another listener on
  
  	DBREASON		m_eUnadviseReason;	//Reason to Unadvise another listener on
  	DBEVENTPHASE	m_eUnadvisePhase;	//Phase to Unadvise another listener on
  
  	HRESULT			m_hrReturn;     // Which HRESULT to return
  	BOOL			m_bFire;        // Indicates weither to fire notifcations at all
  
  	//2D array, of numer of times REASON / PHASE was notified
  	ULONG			m_rgNotified[DBREASON_ALL][DBEVENTPHASE_ALL];
  
  	//2D array, of which REASON / PHASE to fire
  	ULONG			m_rgEvent[DBREASON_ALL][DBEVENTPHASE_ALL];
  	DWORD			m_dwCookie;
  
  	//Reentrant Data
  	DBREASON		m_eReEntrantReason;		
  	DBEVENTPHASE	m_eReEntrantPhase;		
  	void*			m_pReEntrantFunc;		// func to call within the listener
  	void*			m_pReEntrantData;
  
  	//Source information (optional)
  	IID				m_iid;
  	IUnknown*		m_pIUnknown;
  };
  
  
  //REENTRANT_ROWSETFUNC - function to be called from within a listener...
  typedef HRESULT (*REENTRANT_ROWSETFUNC)  (CRowset* pCRowset, IRowset* pIRowset, DBCOUNTITEM cRows, const HROW rghRows[], DBORDINAL cColumns, const DBORDINAL rgColumns[]);
  
  ////////////////////////////////////////////////////////
  // CImpIRowsetNotify
  //
  ////////////////////////////////////////////////////////
  class CImpIRowsetNotify : public IRowsetNotify		//@base public | IRowsetNotify
  {
  	private: //@access private
  		DEFINE_IUNKNOWN_MEMBER_DATA(CImpIRowsetNotify, IRowsetNotify)
  
  	public: //@access public
   		DEFINE_IUNKNOWN_CTOR_DTOR(CImpIRowsetNotify, IRowsetNotify);
  		DEFINE_DELEGATING_QI_ADDREF_RELEASE;
  
  		//IRowsetNotify
  		virtual HRESULT STDMETHODCALLTYPE OnFieldChange( 
  				/* [in] */ IRowset __RPC_FAR *pRowset,
  				/* [in] */ HROW hRow,
  				/* [in] */ DBORDINAL cColumns,
  				/* [size_is][in] */ DBORDINAL __RPC_FAR rgColumns[  ],
  				/* [in] */ DBREASON eReason,
  				/* [in] */ DBEVENTPHASE ePhase,
  				/* [in] */ BOOL fCantDeny);
          
  	    virtual HRESULT STDMETHODCALLTYPE OnRowChange( 
  				/* [in] */ IRowset __RPC_FAR *pRowset,
  				/* [in] */ DBCOUNTITEM cRows,
  				/* [size_is][in] */ const HROW __RPC_FAR rghRows[  ],
  				/* [in] */ DBREASON eReason,
  				/* [in] */ DBEVENTPHASE ePhase,
  				/* [in] */ BOOL fCantDeny);
          
  		virtual HRESULT STDMETHODCALLTYPE OnRowsetChange( 
  				/* [in] */ IRowset __RPC_FAR *pRowset,
  				/* [in] */ DBREASON eReason,
  				/* [in] */ DBEVENTPHASE ePhase,
  				/* [in] */ BOOL fCantDeny);
  
  		//Helpers
  		virtual HRESULT AcceptOrVeto(
  			IRowset*		pIRowset,
  			DBREASON		eReason,		// @parm IN	| Reason for notification
  			DBEVENTPHASE	ePhase, 		// @parm IN	| Phase of event
  			BOOL            fCantDeny,
  			DBCOUNTITEM     cRows       = 0,
  			const HROW		rghRows[]   = NULL,
  			DBORDINAL       cColumns    = 0,
  			const DBORDINAL	rgColumns[] = NULL );
  
  	protected:
  		//data
  };
  
  
  ////////////////////////////////////////////////////////
  // CImpIDBAsynchNotify
  //
  ////////////////////////////////////////////////////////
  class CImpIDBAsynchNotify : public IDBAsynchNotify		//@base public | IDBAsynchNotify
  {
  	private: //@access private
  		DEFINE_IUNKNOWN_MEMBER_DATA(CImpIDBAsynchNotify, IDBAsynchNotify)
  
  	public: //@access public
   		DEFINE_IUNKNOWN_CTOR_DTOR(CImpIDBAsynchNotify, IDBAsynchNotify);
  		DEFINE_DELEGATING_QI_ADDREF_RELEASE;
  
  		//IDBAsynchNotify
  		STDMETHOD(OnLowResource)( 
  			/* [in] */ DB_DWRESERVE dwReserved) ;
  
  		STDMETHOD(OnProgress)( 
  			/* [in] */ HCHAPTER hChapter,
  			/* [in] */ DBASYNCHOP ulOperation,
  			/* [in] */ DBCOUNTITEM ulProgress,
  			/* [in] */ DBCOUNTITEM ulProgressMax,
  			/* [in] */ DBASYNCHPHASE ulAsynchPhase,
  			/* [in] */ LPOLESTR pwszStatusText);
  
  		STDMETHOD(OnStop)( 
  			/* [in] */ HCHAPTER hChapter,
  			/* [in] */ DBASYNCHOP ulOperation,
  			/* [in] */ HRESULT hrStatus,
  			/* [in] */ LPOLESTR pwszStatusText);
          
  	
  		//Helpers
  		virtual HRESULT AcceptOrVeto(
  				HCHAPTER		hChapter,
  				DBASYNCHREASON	eReason,
  				DBASYNCHOP		ulOperation,
  				DBCOUNTITEM		ulProgress,            
  				DBCOUNTITEM		ulProgressMax,            
  				DBASYNCHPHASE	ePhase,
  				LPOLESTR		pwszStatusText);
  
  protected:
  	//Data
  };
  
  
  
  ////////////////////////////////////////////////////////
  // CImpIRowPositionChange
  //
  ////////////////////////////////////////////////////////
  class CImpIRowPositionChange : public IRowPositionChange		//@base public | IRowPositionChange
  {
  	private: //@access private
  		DEFINE_IUNKNOWN_MEMBER_DATA(CImpIRowPositionChange, IRowPositionChange)
  
  	public: //@access public
   		DEFINE_IUNKNOWN_CTOR_DTOR(CImpIRowPositionChange, IRowPositionChange);
  		DEFINE_DELEGATING_QI_ADDREF_RELEASE;
  
  		//IRowPositionChange
  		STDMETHOD(OnRowPositionChange)
  				(
  					DBREASON		eReason, 
  					DBEVENTPHASE	ePhase, 
  					BOOL			fCantDeny
  				);
          
  protected:
  	//Data
  };
  
  
  #endif  // _EXTRALIB_H_