///////////////////////////////////////////////////////////////////////////////////
//
// Microsoft WMIOLE DB Provider
// (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
//
// CBinder object implementation
// 
//
///////////////////////////////////////////////////////////////////////////////////
#include "headers.h"
#include "WmiOleDBMap.h"


///////////////////////////////////////////////////////////////////////////////////
//	Constructor
///////////////////////////////////////////////////////////////////////////////////
CBinder::CBinder(LPUNKNOWN pUnkOuter) : CBaseObj(BOT_BINDER,pUnkOuter)
{
	m_cRef					= 0;

	m_pICreateRow			= NULL;
	m_pIBinderProperties	= NULL;
	m_pIBindResource		= NULL;
	m_pISupportErrorInfo	= NULL;

	m_pDataSrc				= NULL;
	m_pSession				= NULL;

	m_pUrlParser			= NULL;

	m_fDSOInitialized		= FALSE;

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

///////////////////////////////////////////////////////////////////////////////////
//	Destructor
///////////////////////////////////////////////////////////////////////////////////
CBinder::~CBinder()
{
	HRESULT hr = S_OK;
	IDBInitialize *pInitialize = NULL;
	
	SAFE_RELEASE_PTR(m_pSession);

	SAFE_RELEASE_PTR(m_pDataSrc);
	SAFE_DELETE_PTR(m_pICreateRow);
	SAFE_DELETE_PTR(m_pIBinderProperties);
	SAFE_DELETE_PTR(m_pIBindResource);
	SAFE_DELETE_PTR(m_pISupportErrorInfo);

	SAFE_DELETE_PTR(m_pUrlParser);
	SAFE_DELETE_PTR(m_pUtilProp);

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




/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to navigate between the different interfaces
/////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CBinder::QueryInterface ( REFIID riid, LPVOID * ppv)
{
    HRESULT hr = S_OK;


    //======================================================
    //  Check parameters, if not valid return
    //======================================================
    if (NULL == ppv){
        hr = E_INVALIDARG ;
    }
	else
	{
		//======================================================
		//  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_IBindResource)
		{
			*ppv = (LPVOID) m_pIBindResource;
		}
		else if (riid == IID_IDBBinderProperties || riid == IID_IDBProperties)
		{
			*ppv = (LPVOID) m_pIBinderProperties;
		}
		else if (riid == IID_ICreateRow)
		{
			*ppv = (LPVOID) m_pICreateRow;
		}
		else if(riid == IID_ISupportErrorInfo)
		{
			*ppv = (LPVOID)m_pISupportErrorInfo;
		}
		

		//======================================================
		//  If we're going to return an interface, AddRef 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 ) CBinder::AddRef(  void   )
{
    return InterlockedIncrement((long*)&m_cRef);
}

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

    return m_cRef;
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to initialize the binder object
/////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CBinder::InitBinder()
{
	HRESULT	hr		= S_OK;
	BOOL	bRet	= TRUE;

	//================================================
	// Instantiate the data conversion service object
	//================================================
	if( !g_pIDataConvert ){

		hr = CoCreateInstance(CLSID_OLEDB_CONVERSIONLIBRARY, NULL, CLSCTX_INPROC_SERVER, IID_IDataConvert, (void **)&g_pIDataConvert);
	}
	else
	{
		//============================================
		// Already instantiated, increment reference 
		// count
		//============================================
		g_pIDataConvert->AddRef();
	}

	if(SUCCEEDED(hr))
	{
		IDCInfo *pDcInfo = NULL;
		DCINFO dcInfo[1];

		dcInfo[0].eInfoType = DCINFOTYPE_VERSION;
		V_VT(&dcInfo[0].vData) = VT_UI4;
		V_UI4(&dcInfo[0].vData) = 0x200;

		hr = g_pIDataConvert->QueryInterface(IID_IDCInfo,(void **)&pDcInfo);
		hr = pDcInfo->SetInfo(1,dcInfo);

		//================================================
		// Allocate properties management object
		//================================================
		m_pUtilProp = new CUtilProp;
		
		if(m_pUtilProp == NULL)
		{
			hr = E_OUTOFMEMORY;
		}
		else
		// NTRaid: 136443
		// 07/05/00
		if(SUCCEEDED(hr = m_pUtilProp->FInit(BINDERPROP)))
		{
			//================================================
			// Allocate the URLParser class
			//================================================
			m_pUrlParser			= new CURLParser;

			//================================================
			//  Allocate contained interface objects
			//================================================
			m_pIBindResource		= new CImplIBindResource( this );
			m_pICreateRow			= new CImplICreateRow( this );
			m_pIBinderProperties	= new CImplIDBBinderProperties( this );
			m_pISupportErrorInfo	= new CImpISupportErrorInfo(this);

			if(!((BOOL)(m_pUtilProp && m_pUrlParser && m_pIBindResource &&   m_pICreateRow &&  m_pIBinderProperties && m_pISupportErrorInfo)))
			{
				hr = E_OUTOFMEMORY;
			}
		}
	}

	if(SUCCEEDED(hr))
	{
		hr = AddInterfacesForISupportErrorInfo();
	}

    return hr;
}



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

	if(SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IBindResource)))
	if(SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IDBBinderProperties)))
	if(SUCCEEDED(hr = m_pISupportErrorInfo->AddInterfaceID(IID_IDBProperties)))
	{
		hr = m_pISupportErrorInfo->AddInterfaceID(IID_ICreateRow);
	}

	return hr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to Create a Datasource object. The init flat parameter is the flags obtained 
// from the binder flags passed to the IBinderResource::Bind function
// If the caller needs a pointer to a particular interface , then the id of the interface 
// required will be passed in riid parmeter , otherwise this parameter will be GUID_NULL
/////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CBinder::CreateDSO(IUnknown *pUnkOuter,LONG lInitFlag, REFGUID riid,IUnknown ** ppUnk)
{
	HRESULT			hr				= E_FAIL;
	IDBInitialize *	pInitialize		= NULL;
	IDBProperties *	pDBProperties	= NULL;

	DBPROPSET	rgPropertySets[1];
	DBPROPIDSET rgPropIDSet[1];

	DBPROP		rgprop[1];
	VARIANT		varValue;
	ULONG		cPropSets		= 1;
	DBPROPSET*	prgPropertySets;
	DBPROPID	rgPropId[1];



	if(m_pDataSrc != NULL)
	{
		hr = S_OK;
		if( riid != GUID_NULL)
		{
			//=============================================
			// Get the required interface pointer 
			//=============================================
			hr = m_pDataSrc->QueryInterface(riid , (void **)ppUnk);
		}
	}
	else
	{
		memset(&rgprop[0],0,sizeof(DBPROP));
		memset(&rgPropertySets[0],0,sizeof(DBPROPSET));

		VariantInit(&varValue);
		CDataSource *pDatasource = NULL;
		try
		{
			//=============================================
			// Allocate a new datasource object
			//=============================================
			pDatasource = new CDataSource( pUnkOuter );
		}
		catch(...)
		{
			SAFE_DELETE_PTR(pDatasource);
			throw;
		}
		if(pDatasource == NULL)
		{
			hr = E_OUTOFMEMORY;
		}
		else
		if(SUCCEEDED(hr = pDatasource->FInit()))
		{
			//==================================================================
			// QI for IUnknown and save pointer in the member variable
			//==================================================================
			if(SUCCEEDED(hr =pDatasource->QueryInterface(IID_IUnknown , (void **)&m_pDataSrc)))
			if(SUCCEEDED(hr = m_pDataSrc->QueryInterface(IID_IDBProperties ,(void **)&pDBProperties)))
			{
				rgPropIDSet[0].cPropertyIDs		= 0;
				rgPropIDSet[0].guidPropertySet	= DBPROPSET_DBINIT;

				//==================================================================
				// Get the properties set thru IDBBinderProperties
				//==================================================================
				hr = m_pUtilProp->GetProperties(PROPSET_INIT,0,rgPropIDSet, &cPropSets,&prgPropertySets);

				if(SUCCEEDED(hr = pDBProperties->SetProperties(cPropSets,prgPropertySets)))
				{

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


					rgPropId[0]								= DBPROP_INIT_DATASOURCE;

					rgPropIDSet[0].guidPropertySet		= DBPROPSET_DBINIT;
					rgPropIDSet[0].rgPropertyIDs		= rgPropId;
					rgPropIDSet[0].cPropertyIDs		= 1;

					hr = m_pUtilProp->GetProperties( PROPSET_INIT,1, rgPropIDSet,&cPropSets,&prgPropertySets );
					
					if(SUCCEEDED(hr))
					{
						// if the property set is not empty then get the property DBPROP_INIT_DATASOURCE
						// else extract it from URL
						if(prgPropertySets[0].rgProperties[0].vValue.vt == VT_BSTR && 
							prgPropertySets[0].rgProperties[0].vValue.bstrVal != NULL &&
							SysStringLen(prgPropertySets[0].rgProperties[0].vValue.bstrVal) > 0)
						{
							rgprop[0].vValue.bstrVal = Wmioledb_SysAllocString(prgPropertySets[0].rgProperties[0].vValue.bstrVal);
						}
						else
						{
							m_pUrlParser->GetNameSpace(rgprop[0].vValue.bstrVal);
						}
    					
						//==========================================================================
						//  Free memory we allocated to by GetProperties
    					//==========================================================================
						m_pUtilProp->m_PropMemMgr.FreeDBPROPSET( cPropSets, prgPropertySets);

						//==================================================================
						// Get the namespace from the Parser and then set
						// the DBPROP_INIT_DATASOURCE property
						//==================================================================
						rgprop[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
						rgprop[0].vValue.vt		= VT_BSTR;
	//					m_pUrlParser->GetNameSpace(rgprop[0].vValue.bstrVal);

						rgPropertySets[0].rgProperties		= &rgprop[0];
						rgPropertySets[0].cProperties		= 1;
						rgPropertySets[0].guidPropertySet	= DBPROPSET_DBINIT;

						if(SUCCEEDED(hr = pDBProperties->SetProperties(1,rgPropertySets)))
						{
							// set the properties on the current property handler
							hr = m_pUtilProp->SetProperties(PROPSET_INIT,1,rgPropertySets);
						}


						SAFE_FREE_SYSSTRING(rgprop[0].vValue.bstrVal);
					}

					if(SUCCEEDED(hr))
					{
					
						VariantClear(&(rgprop[0].vValue));
															
						//========================================
						// Setting the DBPROP_DBINIT property
						//========================================
						rgprop[0].dwPropertyID = DBPROP_INIT_MODE;
						rgprop[0].vValue.vt =VT_I4;
						rgprop[0].vValue.lVal	= lInitFlag;

						rgPropertySets[0].rgProperties		= &rgprop[0];
						rgPropertySets[0].cProperties		= 1;
						rgPropertySets[0].guidPropertySet	= DBPROPSET_DBINIT;

						if(SUCCEEDED(hr = pDBProperties->SetProperties(1,rgPropertySets)) &&
							SUCCEEDED(hr = m_pUtilProp->SetProperties(PROPSET_INIT,1,rgPropertySets)))
						{
							//===============================================
							// Get the pointer to IDBInitialize interface
							//===============================================
							hr = m_pDataSrc->QueryInterface(IID_IDBInitialize, (void **)&pInitialize);

							//===============================================================
							// Initialize the Datasource object if
							// the flag does not indicate waiting for the initialization
							//===============================================================
							if(!(lInitFlag & DBBINDURLFLAG_WAITFORINIT))
							{
								if(S_OK == (hr = pInitialize->Initialize()))
									m_fDSOInitialized = TRUE;
							}

							if(S_OK == hr)
							{

								if( riid != GUID_NULL)
								{
									//========================================
									// Get the required interface pointer 
									//========================================
									hr = m_pDataSrc->QueryInterface(riid , (void **)ppUnk);
								}
							}
							pInitialize->Release();
							pDBProperties->Release();
						
						} // If(Succeeded(call to SetProperties)) of DBPROP_INIT_MODE property
					
					} // If(Succeeded(call to SetProperties)) of DBPROP_INIT_DATASOURCE property
				
				} // If(Succeeded(call to SetProperties))
			
			} // If Succeeded() for QI
		
		}  // if(Succeeded(pDatasource->FInit()))
		else
		{
			hr = E_FAIL;
		}
	
	}	// Else for if(m_pDataSrc != NULL)

	return hr;
}


/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to create a session object
/////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CBinder::CreateSession(IUnknown *pUnkOuter, REFGUID riid,IUnknown ** ppUnk)
{
	HRESULT hr = S_OK;

	IDBCreateSession *	pDBCreateSession	= NULL;
	IDBInitialize *		pInitialize			= NULL;

	assert(m_pDataSrc != NULL);

	//====================================================================
	// If the datasource is not yet initialized , then initialize it
	//====================================================================
	if(m_fDSOInitialized == FALSE)
	{
		//================================================
		// Get the pointer to IDBInitialize interface
		//================================================
		hr = m_pDataSrc->QueryInterface(IID_IDBInitialize, (void **)&pInitialize);

		if(S_OK == (hr = pInitialize->Initialize()))
		{
			m_fDSOInitialized = TRUE;
		}
		pInitialize->Release();
	}
	
	if(SUCCEEDED(hr))
	if(S_OK ==(hr = m_pDataSrc->QueryInterface(IID_IDBCreateSession,(void **)&pDBCreateSession)))
	{
		//======================
		// Create session
		//======================
		if(S_OK ==(hr = pDBCreateSession->CreateSession(pUnkOuter,IID_IUnknown,(IUnknown**)&m_pSession)))
		{
			if(riid != GUID_NULL)
			{
				hr = m_pSession->QueryInterface(riid,(void **)ppUnk);
			}
		}
	}

	if(pDBCreateSession)
	{
		pDBCreateSession->Release();
	}

	return hr;
}


/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to create a Command object
/////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CBinder::CreateCommand(IUnknown *pUnkOuter, REFGUID guidTemp,IUnknown ** ppUnk)
{

	return m_pSession->CreateCommand(pUnkOuter, guidTemp,ppUnk);

}


/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to create a required row object
// NTRaid:136539 , 136540
// 07/05/00
/////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CBinder::CreateRow(IUnknown *pUnkOuter, REFGUID riid,IUnknown ** ppUnk ,ROWCREATEBINDFLAG rowCreateFlag)
{
	HRESULT				hr			= E_FAIL;
	IUnknown *			pUnkRow		= NULL;
	BSTR				strTable	= NULL;
	BSTR				strPath		= NULL;
	CDBSession *		pDBSess		= NULL;
	ISessionProperties *pSessProp	= NULL;
	CRow *				pNewRow		= NULL;
	DBPROPSET *			pPropSet	= NULL;

	if( S_OK == (hr = m_pSession->QueryInterface(IID_ISessionProperties , (void **)&pSessProp)))
	{

		pDBSess = ((CImpISessionProperties *)pSessProp)->GetSessionPtr();
		
		pSessProp->Release();

		// Get the path of the object
		hr = m_pUrlParser->GetPathWithEmbededInstInfo(strPath);

		// Get the class name 
//		m_pUrlParser->GetClassName(strTable);
		// NTRaid : 134967
		// 07/12/00
		if(SUCCEEDED(hr) && SUCCEEDED(hr = m_pUtilProp->GetConnectionInitProperties(&pPropSet)))
		{
			hr = GetClassName(m_pUrlParser,pPropSet,strTable,m_pDataSrc->m_pWbemWrap);
		}
		
		//==========================================================================
		//  Free memory we allocated to get the namespace property above
		//==========================================================================
		CPropertyMemoryMgr::FreeDBPROPSET( 1, pPropSet);

		if(SUCCEEDED(hr))
		{
			try
			{
				// currently hardcoded to NO_QUALIFIERS 
				pNewRow = new CRow(pUnkOuter,pDBSess);
			}
			catch(...)
			{
				SAFE_DELETE_PTR(pNewRow);
				throw;
			}


			if( pNewRow == NULL)
			{
				hr = E_OUTOFMEMORY;
			}
			else
			{
				if(S_OK ==(hr = pNewRow->InitRow(strPath,strTable,-1,rowCreateFlag)))
				{
					hr = pNewRow->QueryInterface(riid,(void **)ppUnk);
				}

				if(hr == S_OK && rowCreateFlag != ROWOPEN)
				{
					hr = pNewRow->UpdateKeysForNewInstance();
				}
			}
			//========================================================
			// Free the strings allocated by the URLParser class
			//========================================================
			SysFreeString(strTable);
			SysFreeString(strPath);
		}
		
		if(FAILED(hr))
		{
			SAFE_DELETE_PTR(pNewRow);
			*ppUnk = NULL;
		}
	}

	return hr;
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Function to create a Rowset object
/////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CBinder::CreateRowset(IUnknown *pUnkOuter, REFGUID riid,IUnknown ** ppUnk)
{
	HRESULT			hr			= E_FAIL;
	IOpenRowset *	pOpenRowset	= NULL;
	DBPROPSET *		pPropSet	= NULL;
	ULONG			cPropSets	= 1;

	DBPROPSET*	prgPropertySets	= NULL;
	BSTR		strTableName = NULL;

	assert(m_pSession != NULL);

   	//=========================================
	// Get pointer to IOpenRowset interface
   	//=========================================
	if(S_OK == (hr = m_pSession->QueryInterface(IID_IOpenRowset , (void **)&pOpenRowset)))
	{
		DBPROPIDSET rgPropIDSet[1];
		rgPropIDSet[0].cPropertyIDs		= 0;
		rgPropIDSet[0].guidPropertySet	= DBPROPSET_ROWSET;

	   	//=========================================
		// Get the properties
	   	//=========================================
		hr = m_pUtilProp->GetProperties(PROPSET_ROWSET,0,rgPropIDSet, &cPropSets,&prgPropertySets);

	   	//=========================================
		// Get the class name and initialize the tableID
	   	//=========================================
		// NTRaid : 134967
		// 07/12/00
		if(SUCCEEDED(hr))
		{		
			if (SUCCEEDED(hr = m_pUtilProp->GetConnectionInitProperties(&pPropSet)))
			{
				hr = GetClassName(m_pUrlParser,pPropSet,strTableName,m_pDataSrc->m_pWbemWrap);

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

	   				//=========================================
					// Open the rowset
	   				//=========================================
					hr = pOpenRowset->OpenRowset(pUnkOuter,&tableID,NULL,riid,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);
		}
	}

	SAFE_RELEASE_PTR(pOpenRowset);

	return hr;
}


/*
///////////////////////////////////////////////////////////////////////////////////////////////////
// Get Binding flags and put it in a variable as INIT_MODE flags
///////////////////////////////////////////////////////////////////////////////////////////////////
void CBinder::GetInitAndBindFlagsFromBindFlags(DBBINDURLFLAG dwBindURLFlags,LONG & lInitMode ,LONG & lInitBindFlags)
{

	lInitMode = 0;
	lInitBindFlags = 0;

	// DBPROP_INIT_MODE
	if(DBBINDURLFLAG_READ & dwBindURLFlags)
	{
		lInitMode = lInitMode | DB_MODE_READ;
	}

	if(DBBINDURLFLAG_WRITE & dwBindURLFlags)
	{
		lInitMode = lInitMode | DB_MODE_WRITE;
	}

	if(DBBINDURLFLAG_SHARE_DENY_READ & dwBindURLFlags)
	{
		lInitMode = lInitMode | DB_MODE_SHARE_DENY_READ;
	}

	if(DBBINDURLFLAG_SHARE_DENY_WRITE & dwBindURLFlags)
	{
		lInitMode = lInitMode | DB_MODE_SHARE_DENY_WRITE;
	}

	if(DBBINDURLFLAG_SHARE_EXCLUSIVE & dwBindURLFlags)
	{
		lInitMode = lInitMode | DB_MODE_SHARE_EXCLUSIVE;
	}

	if(DBBINDURLFLAG_SHARE_DENY_NONE & dwBindURLFlags)
	{
		lInitMode = lInitMode | DB_MODE_SHARE_DENY_NONE;
	}

	// DBPROP_INIT_BINDFLAGS
	if(DBBINDURLFLAG_RECURSIVE & dwBindURLFlags)
	{
		lInitBindFlags = lInitBindFlags | DB_BINDFLAGS_RECURSIVE;
	}

	if(DBBINDURLFLAG_OUTPUT & dwBindURLFlags)
	{
		lInitBindFlags = lInitBindFlags | DB_BINDFLAGS_OUTPUT;
	}

	if(DBBINDURLFLAG_DELAYFETCHCOLUMNS & dwBindURLFlags)
	{
		lInitBindFlags = lInitBindFlags | DB_BINDFLAGS_DELAYFETCHCOLUMNS;
	}

	if(DBBINDURLFLAG_DELAYFETCHSTREAM & dwBindURLFlags)
	{
		lInitBindFlags = lInitBindFlags | DB_BINDFLAGS_DELAYFETCHSTREAM;
	}



}
*/
////////////////////////////////////////////////////////////
// Function to release all the bound objects
////////////////////////////////////////////////////////////
HRESULT CBinder::ReleaseAllObjects()
{
	SAFE_RELEASE_PTR(m_pDataSrc);
	SAFE_RELEASE_PTR(m_pSession);
	
	return S_OK;

}