//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Microsoft WMIOLE DB Provider
// (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
//
//
//  CDBSession object implementation
//
// NTRaid:: 139685 Transaction support removed
//////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "headers.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Constructor for this class
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
CDBSession::CDBSession(  LPUNKNOWN pUnkOuter )  : CBaseObj(BOT_SESSION, pUnkOuter)
{
	//==========================================================================
	// Initialize simple member vars
	//==========================================================================
	m_nOpenedRowset		= 0;
	m_bTxnStarted		= FALSE;

	//==========================================================================
	// Initially, NULL all contained interfaces
	//==========================================================================
	m_pIGetDataSource		= NULL;
	m_pIOpenRowset			= NULL;
    m_pISchemaRowset        = NULL;
	m_pIDBCreateCommand     = NULL;
	m_pISessionProperties	= NULL;
	m_pUtilProp				= NULL;
	m_pITableDefinition		= NULL;					
	m_pISessionCache		= NULL;
	m_pIBindResource		= NULL;
	m_pIIndexDefinition		= NULL;
	m_pIAlterTable			= NULL;
	m_pISupportErrorInfo	= NULL;
	m_pITransLocal			= NULL;
	//==========================================================================
	// Pointer to parent object
	//==========================================================================
	m_pCDataSource		= NULL;

	memset(&m_TxnGuid , 0 , sizeof(XACTUOW));

	//==========================================================================
	// Increment global object count.
	//==========================================================================
	InterlockedIncrement(&g_cObj);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Destructor for this class
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
CDBSession:: ~CDBSession ( void  )
{
	//===========================================================================
    // Free properties management object
	//===========================================================================
    SAFE_DELETE_PTR( m_pUtilProp );

	//===========================================================================
    // Free contained interfaces
	//===========================================================================
    SAFE_DELETE_PTR( m_pIGetDataSource );
    SAFE_DELETE_PTR( m_pIOpenRowset );
    SAFE_DELETE_PTR( m_pISchemaRowset );
    SAFE_DELETE_PTR( m_pIDBCreateCommand );
    SAFE_DELETE_PTR( m_pISessionProperties );
    SAFE_DELETE_PTR( m_pITableDefinition );
	SAFE_DELETE_PTR(m_pIBindResource);
	SAFE_DELETE_PTR(m_pIIndexDefinition);
	SAFE_DELETE_PTR(m_pIAlterTable);
	SAFE_DELETE_PTR(m_pISupportErrorInfo);
//	SAFE_DELETE_PTR(m_pITransLocal);
	
	
	m_pCDataSource->RemoveSession();
	m_pCDataSource->GetOuterUnknown()->Release();

	//===========================================================================
    // Decrement global object count.
	//===========================================================================
    InterlockedDecrement(&g_cObj);
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Initialize the command Object
//
//  Did the Initialization Succeed
//        TRUE		Initialization succeeded
//        FALSE		Initialization failed
//////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CDBSession::FInit ( CDataSource  *pCDataSource   )
{
	HRESULT hr = E_OUTOFMEMORY;
	//===========================================================================
	// Establish parent object pointer
	//===========================================================================
	assert( pCDataSource );
	m_pCDataSource	= pCDataSource;
	m_pCDataSource->GetOuterUnknown()->AddRef();

	//===========================================================================
	// Allocate properties management object
	//===========================================================================
	m_pUtilProp = new CUtilProp;

	// NTRaid: 136443
	// 07/05/00
	if(m_pUtilProp == NULL)
	{
		hr = E_OUTOFMEMORY;
	}
	else
	if(SUCCEEDED(hr = m_pUtilProp->FInit(SESSIONPROP)))
	{
		//===========================================================================
		// Allocate contained interface objects
		//===========================================================================
		m_pIGetDataSource		= new CImpIGetDataSource( this );
		m_pIOpenRowset			= new CImpIOpenRowset( this );
		m_pISchemaRowset    	= new CImpIDBSchemaRowset( this );
		m_pIDBCreateCommand    	= new CImpIDBCreateCommand( this );
		m_pISessionProperties	= new CImpISessionProperties( this );
		m_pITableDefinition		= new CImpITableDefinition( this );
		m_pIBindResource		= new CImplIBindRsrc( this );
		m_pIIndexDefinition		= new CImplIIndexDefinition( this );
		m_pIAlterTable			= new CImplIAlterTable( this );
		m_pISupportErrorInfo	= new CImpISupportErrorInfo(this);
		// Removing transaction support as per alanbos mail ( core is removing the support)
		// 06/30/2000
	//	m_pITransLocal			= new CImpITransactionLocal(this);

		if( m_pIGetDataSource && m_pIOpenRowset && m_pIDBCreateCommand && m_pISchemaRowset && m_pISessionProperties && 	
						m_pITableDefinition && m_pIBindResource && m_pIIndexDefinition && m_pIAlterTable) // && m_pITransLocal)
		{
			hr = S_OK;
		}
		else
		{
			hr = E_OUTOFMEMORY;
		}
	}
	if(SUCCEEDED(hr))
	{
		hr = AddInterfacesForISupportErrorInfo();
	}
	
	return hr;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to add interfaces to ISupportErrorInfo interface
/////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CDBSession::AddInterfacesForISupportErrorInfo()
{
	HRESULT hr = S_OK;

	if(	SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IGetDataSource))		&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IOpenRowset))			&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IDBSchemaRowset))		&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_ISessionProperties))	&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_ITableDefinition))		&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IBindResource))			&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IDBCreateCommand))		&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IIndexDefinition))		&&
		SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_ITransactionLocal)))
	{
		hr = m_pISupportErrorInfo->AddInterfaceID(IID_IAlterTable);
	}

	return hr;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces 
//  the called object supports.
//
//  HRESULT indicating the status of the method
//       S_OK           Interface is supported and ppvObject is set.
//       E_NOINTERFACE  Interface is not supported by the object
//       E_INVALIDARG   One or more arguments are invalid.
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDBSession::QueryInterface (   REFIID riid,        // IN | Interface ID of the interface being queried for.
											LPVOID * ppv    )   // OUT | Pointer to interface that was instantiated
{
	HRESULT hr = E_INVALIDARG;

	if(CheckIfValidDataSrc() == FALSE)
		return g_pCError->PostHResult(hr,&IID_IUnknown);
	
	//============================================================================
    // Is the pointer bad?
	//============================================================================
    if (ppv != NULL){

		//========================================================================
		//  Place NULL in *ppv in case of failure
		//========================================================================
		*ppv = NULL;

		//========================================================================
		//  This is the non-delegating IUnknown implementation
		//========================================================================
		if (riid == IID_IUnknown)
			*ppv = (LPVOID) this;
		else if (riid == IID_IGetDataSource)
			*ppv = (LPVOID) m_pIGetDataSource;
		else if (riid == IID_IOpenRowset)
			*ppv = (LPVOID) m_pIOpenRowset;
		else if (riid == IID_IDBSchemaRowset)
			*ppv = (LPVOID) m_pISchemaRowset;
		else if (riid == IID_ISessionProperties)
			*ppv = (LPVOID) m_pISessionProperties;
		else if (riid == IID_ITableDefinition)				
			*ppv = (LPVOID) m_pITableDefinition;
		else if (riid == IID_IBindResource)				
			*ppv = (LPVOID) m_pIBindResource;
        else if ( riid == IID_IDBCreateCommand )
    		*ppv = (LPVOID)m_pIDBCreateCommand;
		else if ( riid == IID_IIndexDefinition)
			*ppv = (LPVOID)m_pIIndexDefinition;
		else if ( riid == IID_IAlterTable)
			*ppv = (LPVOID)m_pIAlterTable;
	// Removing transaction support as per alanbos mail ( core is removing the support)
	// 06/30/2000
//		else if ( riid == IID_ITransactionLocal || riid == IID_ITransaction)
//			*ppv = (LPVOID)m_pITransLocal;
		else if ( riid == IID_ISupportErrorInfo)
			*ppv = (LPVOID)m_pISupportErrorInfo;
	
		

		//========================================================================
		//  If we're going to return an interface, AddRef it first
		//========================================================================
		if (*ppv){

			((LPUNKNOWN) *ppv)->AddRef();
			hr = S_OK;
		}
		else{
			hr = E_NOINTERFACE;
		}
	}
	return hr;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Increments a persistence count for the object
//
//  Current reference count
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CDBSession::AddRef (  void   )
{
    return InterlockedIncrement((long *)&m_cRef);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Decrements a persistence count for the object and if persistence count is 0, the object destroys itself.
//
//  Current reference count
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CDBSession::Release (  void    )
{
     if (!InterlockedDecrement((long *)&m_cRef)){
        delete this;
        return 0;
    }
    return m_cRef;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Gets a particular datasource property
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CDBSession::GetDataSrcProperty(DBPROPID propId , VARIANT & varValue)
{
    return m_pCDataSource->GetDataSrcProperty(propId,varValue);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Creates a new command called by IBindResource implementation of the session
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CDBSession::CreateCommand(IUnknown *pUnkOuter, REFGUID riid,IUnknown ** ppCommand)
{
	HRESULT		hr		= S_OK;
	CCommand*	pcmd	= NULL;


	if(CheckIfValidDataSrc() == FALSE)
	{
		hr = E_INVALIDARG;
	}
	else
	{

		//=========================================================================
		// Initialize output param
		//=========================================================================
		if (ppCommand)
		{
			*ppCommand = NULL;
		}

		//=========================================================================
		// Check Function Arguments
		//=========================================================================
		if( ppCommand == NULL )
		{
			hr = E_INVALIDARG;
		}
		else
		//=========================================================================
		// The outer object must explicitly ask for IUnknown
		//=========================================================================
		if (pUnkOuter != NULL && riid != IID_IUnknown)
		{
			hr = DB_E_NOAGGREGATION;
		}
		else
		{

			try
			{
				//=========================================================================
				// This is the outer unknown from the user, for the new Command,
				// not to be confused with the outer unknown of this DBSession object.
				//=========================================================================
				pcmd = new CCommand(this, pUnkOuter);
			}
			catch(...)
			{
				SAFE_DELETE_PTR(pcmd);
				throw;
			}
			if (pcmd)
			{
		/*        //=====================================================================
				// Need to increment usage count since passed out to  CCommand
				//=====================================================================
				m_pCDBSession->AddRef();
		*/
				//=====================================================================
				// Initialize the command
				//=====================================================================
				hr = pcmd->FInit();
				if( SUCCEEDED(hr) )
				{
					hr = pcmd->QueryInterface( riid, (void **) ppCommand );
					if( SUCCEEDED(hr) )
					{
						// If everything is fine then set the datasource persist info to dirty 
						m_pCDataSource->SetPersistDirty();
					}

					//=================================================================
					// Need to drop through on error, so command object is destroyed
					//=================================================================
				}
				else
				{
					SAFE_DELETE_PTR(pcmd);
				}
			}
			else
			{
				//=====================================================================
				// Since Ctor failed, it cannot know to Release pUnkOuter, 
				// so we must do it here since we are owner.
				//=====================================================================
				if (pUnkOuter)
				{
					pUnkOuter->Release();
				}
				hr = E_OUTOFMEMORY;
			}
		
		}	// else for NOAGGREGATION

	}	// else for INVALID_ARG

	return hr;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Creates a new Row called by IBindResource implementation of the session
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CDBSession::CreateRow(IUnknown *pUnkOuter, WCHAR *pstrURL,REFGUID guidTemp,IUnknown ** ppUnk)
{
	HRESULT		hr			= E_FAIL;
	CRow *		pNewRow		= NULL;
	DBPROPSET *	pPropSet	= NULL;
	BSTR		strTable;
	BSTR		strPath;
	CURLParser  urlParser;
	
	strPath = Wmioledb_SysAllocString(pstrURL);
	// Modified on 06/09/00
	// Bug while getting a row from ADO Row object
//	urlParser.SetPath(strPath);
	urlParser.SetURL(strPath);
	SysFreeString(strPath);

	if(CheckIfValidDataSrc() == FALSE)
	{
		hr = E_INVALIDARG;
	}
	else
	{

		//===================================
		// Get the path of the object
		//===================================
		if(SUCCEEDED(hr = urlParser.GetPathWithEmbededInstInfo(strPath)))
		{
			//===================================
			// Get the class name 
			//===================================
			// NTRaid:134967
			// 07/11/2000
			if(SUCCEEDED(hr) && SUCCEEDED(hr = m_pCDataSource->GetConnectionInitProperties(&pPropSet)))
			{
				hr = GetClassName(&urlParser,pPropSet,strTable,m_pCDataSource->m_pWbemWrap);

				//==========================================================================
				//  Free memory we allocated to get the namespace property above
				//==========================================================================
				CPropertyMemoryMgr::FreeDBPROPSET( 1, pPropSet);
			}

			try
			{
				pNewRow = new CRow(pUnkOuter,this);
			}
			catch(...)
			{
				SAFE_DELETE_PTR(pNewRow);
				throw;
			}

			if(SUCCEEDED(hr) && SUCCEEDED(hr = pNewRow->InitRow(strPath,strTable)))
			{
				hr = pNewRow->QueryInterface(guidTemp,(void **)ppUnk);
			}
			//=====================================================
			// Free the strings allocated by the URLParser class
			//=====================================================
			SysFreeString(strTable);
			SysFreeString(strPath);

			if(FAILED(hr))
			{
				SAFE_DELETE_PTR(pNewRow);
				*ppUnk = NULL;
			}
		}
	
	}	// INVALIDARG

	return hr;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Creates a new Rowset called by IBindResource implementation of the session
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CDBSession::CreateRowset(IUnknown *pUnkOuter, WCHAR *pstrURL, REFGUID guidTemp,IUnknown ** ppUnk)
{
	HRESULT hr = E_FAIL;
	
	ULONG		cPropSets = 0;
	DBPROPSET*	prgPropertySets = NULL;
	BSTR		strTableName = NULL;
	CURLParser  urlParser;
	DBPROPSET *	pPropSet	= NULL;
	
	{
		CBSTR strTemp;
		strTemp.SetStr(pstrURL);
		urlParser.SetURL(pstrURL);
	}

	if(CheckIfValidDataSrc() == FALSE)
	{
		hr =E_INVALIDARG;
	}
	else
	{

		DBPROPIDSET rgPropIDSet[1];
		rgPropIDSet[0].cPropertyIDs		= 0;
		rgPropIDSet[0].guidPropertySet	= DBPROPSET_ROWSET;

		//===============================
		// Get the properties
		//===============================
		if(SUCCEEDED(hr = m_pUtilProp->GetProperties(PROPSET_ROWSET,0,rgPropIDSet, &cPropSets,&prgPropertySets)))
		{
			//====================================================
			// Get the class name and initialize the tableID
			//====================================================
			// NTRaid:134967
			// 07/11/2000
			if( SUCCEEDED(hr = m_pCDataSource->GetConnectionInitProperties(&pPropSet)) )
			{
				hr = GetClassName(&urlParser,pPropSet,strTableName,m_pCDataSource->m_pWbemWrap);

				if (SUCCEEDED(hr))
				{

					DBID tableID;
					memset(&tableID , 0 , sizeof(DBID));
					tableID.eKind = DBKIND_NAME;
					tableID.uName.pwszName = strTableName;

					//===============================
					// Open the rowset
					//===============================
					hr = m_pIOpenRowset->OpenRowset(pUnkOuter,&tableID,NULL,guidTemp,cPropSets,prgPropertySets,ppUnk);

					SAFE_FREE_SYSSTRING(strTableName);
				}

				//==========================================================================
				//  Free memory we allocated to get the namespace property above
				//==========================================================================
				CPropertyMemoryMgr::FreeDBPROPSET( 1, pPropSet);
			}

			//==========================================================================
			//  Free memory we allocated to by GetProperties
			//==========================================================================
			m_pUtilProp->m_PropMemMgr.FreeDBPROPSET( cPropSets, prgPropertySets);
		}
	}

	return hr;
}

BOOL CDBSession::CheckIfValidDataSrc()
{
	if(m_pCDataSource != NULL && m_pCDataSource->m_fDSOInitialized == TRUE)
		return TRUE;


	return FALSE;

}

HRESULT CDBSession::GenerateNewUOW(GUID &guidTrans)
{
	HRESULT hr = S_OK;
	assert (sizeof(XACTUOW) == sizeof(GUID));
	if(SUCCEEDED(hr = CoCreateGuid(&guidTrans)))
	{
		memcpy(&m_TxnGuid.rgb,&guidTrans,sizeof(GUID));
	}
	return hr;
}

void CDBSession::AddRowset(CBaseRowObj * pRowset)
{
	m_nOpenedRowset++;
	m_OpenedRowsets.Add(pRowset);
}

void CDBSession::RemoveRowset(CBaseRowObj * pRowset)
{
	m_nOpenedRowset--;
	for( int i = 0 ; i < m_OpenedRowsets.Size(); i++)
	{
		if(pRowset == (CBaseRowObj *) m_OpenedRowsets.GetAt(i))
		{
			m_OpenedRowsets.RemoveAt(i);
			break;
		}
	}
	m_OpenedRowsets.Add(pRowset);
}

void CDBSession::SetAllOpenRowsetToZoombieState()
{
	CBaseRowObj * pRowObj = NULL;
	m_nOpenedRowset--;
	for( int i = 0 ; i < m_OpenedRowsets.Size(); i++)
	{
		pRowObj = (CBaseRowObj *) m_OpenedRowsets.GetAt(i);
		if(pRowObj != NULL)
		{
			pRowObj->SetStatusToZoombie();
		}
		pRowObj = NULL;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Retrieve an interface pointer on the session object
//
//  
//		 S_OK				Session Object Interface returned
//		 E_INVALIDARG		ppDataSource was NULL
//		 E_NOINTERFACE		IID not supported
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIGetDataSource::GetDataSource(	REFIID		riid,			//  IN  IID desired
												IUnknown**	ppDataSource	//  OUT ptr to interface
	)
{
	HRESULT hr = E_INVALIDARG;
    CSetStructuredExceptionHandler seh;

	TRY_BLOCK;

	// Seriliaze the object
	CAutoBlock cab(m_pObj->GetCriticalSection());

	// Clear ErrorInfo
	g_pCError->ClearErrorInfo();

	//========================================================================
	// Check Function Arguments
	//========================================================================
	if( ppDataSource != NULL ){
	
		assert(m_pObj->m_pCDataSource);
		assert(m_pObj->m_pCDataSource->GetOuterUnknown());
	
		//====================================================================
		//Handle Aggregated DataSource (if aggregated)
		//====================================================================
		hr = m_pObj->m_pCDataSource->GetOuterUnknown()->QueryInterface(riid, (LPVOID*)ppDataSource);
	}
	hr = hr == S_OK ? hr :g_pCError->PostHResult(hr,&IID_IGetDataSource);

	CATCH_BLOCK_HRESULT(hr,L"IGetDataSource::GetDataSource");
	return hr;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Returns current settings of all properties in the DBPROPFLAGS_SESSION property group
//  HRESULT
//       S_OK           The method succeeded
//       E_INVALIDARG   pcProperties or prgPropertyInfo was NULL
//       E_OUTOFMEMORY  Out of memory
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpISessionProperties::GetProperties (
	    ULONG				cPropertySets,		// IN   count of restiction guids
		const DBPROPIDSET	rgPropertySets[],	// IN   restriction guids
		ULONG*              pcProperties,		// OUT  count of properties returned
		DBPROPSET**			prgProperties		// OUT  property information returned
    )
{
    assert( m_pObj );
    assert( m_pObj->m_pUtilProp );
	HRESULT hr = S_OK;

    CSetStructuredExceptionHandler seh;

	TRY_BLOCK;

	// Seriliaze the object
	CAutoBlock cab(m_pObj->GetCriticalSection());

	g_pCError->ClearErrorInfo();

	//========================================================================
	// Check Arguments
	//========================================================================
	hr = m_pObj->m_pUtilProp->GetPropertiesArgChk(PROPSET_SESSION, cPropertySets, 
								rgPropertySets, pcProperties, prgProperties);
	if ( !FAILED(hr) ){

		//========================================================================
		// just pass this call on to the utility object that manages our 
		// properties
		//========================================================================
		hr = m_pObj->m_pUtilProp->GetProperties( PROPSET_SESSION,cPropertySets,rgPropertySets,pcProperties, prgProperties );
	}
	hr = hr == S_OK ? hr :g_pCError->PostHResult(hr,&IID_ISessionProperties);

	CATCH_BLOCK_HRESULT(hr,L"ISessionProperties::GetProperties ");
	return hr;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Set properties in the DBPROPFLAGS_SESSION property group
//
//  HRESULT
//       E_INVALIDARG   cProperties was not equal to 0 and rgProperties was NULL
//       E_NOTIMPL		this method is not implemented
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP    CImpISessionProperties::SetProperties (   ULONG		cProperties, DBPROPSET	rgProperties[] )
{
 	HRESULT hr = S_OK;

    assert( m_pObj );
    assert( m_pObj->m_pUtilProp );

    CSetStructuredExceptionHandler seh;

	TRY_BLOCK;

	// Seriliaze the object
	CAutoBlock cab(m_pObj->GetCriticalSection());
	
	// Clear Error information
	g_pCError->ClearErrorInfo();

	//========================================================================
	// Quick return if the Count of Properties is 0
	//========================================================================
	if( cProperties != 0 ){

		//====================================================================
		// Check Arguments for use by properties
		//====================================================================
		hr = m_pObj->m_pUtilProp->SetPropertiesArgChk(cProperties, rgProperties);
		if( !FAILED(hr) ){

			//====================================================================
		    // just pass this call on to the utility object that manages our properties
			//====================================================================
			hr = m_pObj->m_pUtilProp->SetProperties( PROPSET_SESSION,cProperties, rgProperties);
		}
	}
	hr = hr == S_OK ? hr :g_pCError->PostHResult(hr,&IID_ISessionProperties);

	CATCH_BLOCK_HRESULT(hr,L"ISessionProperties::GetProperties ");
	return hr;
}