2025-11-28 00:35:46 +09:00

1066 lines
27 KiB
C++

//--------------------------------------------------------------------
// Microsoft OLE DB Sample Provider
// (C) Copyright 1991 - 1999 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @module BINDER.CPP | CBinder object implementation and contained
// interfaces
//
//
// Includes ------------------------------------------------------------------
#include "headers.h"
// Globals -------------------------------------------------------------------
WCHAR g_wszDataSourceKeyword[] = L"DataSource";
WCHAR g_wszFileKeyword[] = L"File";
WCHAR g_wszRowKeyword[] = L"Row";
// Code ----------------------------------------------------------------------
// CBinder::CBinder ----------------------------------------------------------
//
// @mfunc Constructor for this class
//
// @rdesc NONE
//
CBinder::CBinder
(
LPUNKNOWN pUnkOuter //@parm IN | Outer Unkown Pointer
) // invoke ctor for base class
: CBaseObj( BOT_BINDER )
{
m_cRef = 0;
m_pUnkOuter = pUnkOuter ? pUnkOuter : this;
m_pUtilProp = NULL;
// Contained interfaces
m_pIBindResource = NULL;
m_pIDBBinderProperties = NULL;
m_pICreateRow = NULL;
}
// CBinder::~CBinder ---------------------------------------------------------
//
// @mfunc Destructor for this class
//
// @rdesc NONE
//
CBinder::~CBinder()
{
SAFE_DELETE( m_pUtilProp );
SAFE_DELETE( m_pIBindResource );
SAFE_DELETE( m_pIDBBinderProperties );
SAFE_DELETE( m_pICreateRow );
}
// CBinder::FInit ------------------------------------------------------------
//
// @mfunc Initialize the Binder Object
//
// @rdesc Did the Initialization Succeed
// @flag TRUE | Initialization succeeded
// @flag FALSE | Initialization failed
//
BOOL CBinder::FInit()
{
assert(m_pUnkOuter);
m_pUtilProp = new CUtilProp();
// contained interfaces
m_pIBindResource = new CImpIBindResource( this, m_pUnkOuter );
m_pIDBBinderProperties = new CImpIDBBinderProperties( this, m_pUnkOuter );
m_pICreateRow = new CImpICreateRow( this, m_pUnkOuter );
return (m_pUtilProp && m_pIBindResource && m_pIDBBinderProperties &&
m_pICreateRow);
}
// CBinder::QueryInterface ---------------------------------------------------
//
// @mfunc Returns a pointer to a specified interface. Callers use
// QueryInterface to determine which interfaces the called object
// supports.
//
// @rdesc HRESULT indicating the status of the method
// @flag S_OK | Interface is supported and ppvObject is set.
// @flag E_NOINTERFACE | Interface is not supported by the object
// @flag E_INVALIDARG | One or more arguments are invalid.
//
STDMETHODIMP CBinder::QueryInterface
(
REFIID riid,
LPVOID * ppv
)
{
if (NULL == ppv)
return ResultFromScode( E_INVALIDARG );
// Place NULL in *ppv in case of failure
*ppv = NULL;
//IUNKNOWN
if (riid == IID_IUnknown)
*ppv = this;
else if(riid == IID_IBindResource)
*ppv = (LPVOID) m_pIBindResource;
else if(riid == IID_IDBProperties)
*ppv = (LPVOID) m_pIDBBinderProperties;
else if(riid == IID_IDBBinderProperties)
*ppv = (LPVOID) m_pIDBBinderProperties;
else if(riid == IID_ICreateRow)
*ppv = (LPVOID) m_pICreateRow;
// If we're going to return an interface, AddRef it first
if (*ppv)
{
((LPUNKNOWN) *ppv)->AddRef();
return ResultFromScode( S_OK );
}
else
return ResultFromScode( E_NOINTERFACE );
}
// CBinder::AddRef -----------------------------------------------------------
//
// @mfunc Increments a persistence count for the object
//
// @rdesc Current reference count
//
STDMETHODIMP_( DBREFCOUNT ) CBinder::AddRef
(
void
)
{
return ++m_cRef;
}
// CBinder::Release ----------------------------------------------------------
//
// @mfunc Decrements a persistence count for the object and if
// persistence count is 0, the object destroys itself.
//
// @rdesc HRESULT indicating the status of the method
// @flag S_OK | Interface is supported and ppvObject is set.
// @flag E_NOINTERFACE | Interface is not supported by the object
// @flag E_INVALIDARG | One or more arguments are invalid.
//
STDMETHODIMP_( ULONG ) CBinder::Release
(
void
)
{
if (!--m_cRef)
{
delete this;
return 0;
}
return m_cRef;
}
// CImpIBindResource::BindDSO ------------------------------------------------
//
// @mfunc Returns an initialized datasource object
//
// @rdesc
// @flag S_OK | Method succeeded
// @flag E_OUTOFMEMORY | Out of memory
// @flag OTHER | Other HRESULTs returned by called functions
//
HRESULT CImpIBindResource::BindDSO
(
IUnknown * pUnkOuter, // [in] controllig IUnknown
REFIID riid, // [in] interface to be requested
BOOL fWaitForInit, // [in] flag indicating if DSO should be initialized
WCHAR * pwszDataSource, // [in] datasource path
IUnknown ** ppUnk // [out] interface retrieved on DSO
)
{
HRESULT hr = E_FAIL;
IGetDataSource * pIGetDataSource = NULL;
IDBProperties * pIDBProperties = NULL;
IDBInitialize * pIDBInitialize = NULL;
CDataSource * pDataSource = NULL;
ULONG cPropSets = 0;
DBPROPSET * rgPropSets = NULL;
if( BOT_SESSION == m_pObj->GetBaseObjectType() )
{
// In this case the datasource is alreay initialized
if( fWaitForInit )
return E_INVALIDARG;
// Obtain an instance of the current session Session::IBindResource
// pUnkOuter is always ignored when the DSO already exists
TESTC(hr = ((CDBSession*)m_pObj)->QueryInterface(IID_IGetDataSource, (void**)&pIGetDataSource));
TESTC(hr = pIGetDataSource->GetDataSource(riid, ppUnk));
}
else
{
// create DSO (aggregating if necessary)
pDataSource = new CDataSource(pUnkOuter);
if( pDataSource == NULL || !pDataSource->FInit() )
{
hr = E_OUTOFMEMORY;
SAFE_DELETE(pDataSource);
goto CLEANUP;
}
// initialize the DSO with the cached properties
TESTC(hr = pDataSource->QueryInterface(IID_IDBProperties, (void**)&pIDBProperties));
TESTC(hr = pDataSource->QueryInterface(IID_IDBInitialize, (void**)&pIDBInitialize));
// Get the cached initialization properties
// and set them on the requested DataSource
TESTC(hr = ((CBinder*)m_pObj)->m_pUtilProp->GetProperties(PROPSET_DSO, 0,
NULL, &cPropSets, &rgPropSets));
TESTC(hr = pIDBProperties->SetProperties(cPropSets, rgPropSets));
// Set the DBPROP_INIT_DATASOURCE property if specified in the URL
if( pwszDataSource )
{
DBPROPSET PropSet;
DBPROP PropDataSource;
PropSet.guidPropertySet = DBPROPSET_DBINIT;
PropSet.rgProperties = &PropDataSource;
PropSet.cProperties = 1;
PropDataSource.dwPropertyID = DBPROP_INIT_DATASOURCE;
PropDataSource.dwOptions = DBPROPOPTIONS_REQUIRED;
PropDataSource.dwStatus = 0;
V_VT(&PropDataSource.vValue) = VT_BSTR;
V_BSTR(&PropDataSource.vValue) = SysAllocString(pwszDataSource);
if( FAILED(hr = pIDBProperties->SetProperties(1, &PropSet)) )
{
VariantClear(&PropDataSource.vValue);
goto CLEANUP;
}
VariantClear(&PropDataSource.vValue);
}
if( !fWaitForInit )
{
// Initialize
TESTC(hr = pIDBInitialize->Initialize());
}
// Return the requested interface
TESTC(hr = pDataSource->QueryInterface(riid, (void**)ppUnk));
}
hr = S_OK;
CLEANUP:
// release properties
FreeProperties(&cPropSets, &rgPropSets);
SAFE_RELEASE(pIGetDataSource);
SAFE_RELEASE(pIDBProperties);
SAFE_RELEASE(pIDBInitialize);
return hr;
}
// CImpIBindResource::BindSession --------------------------------------------
//
// @mfunc Returns a session object
//
// @rdesc
// @flag S_OK | Method succeeded
// @flag OTHER | Other HRESULTs returned by called functions
//
HRESULT CImpIBindResource::BindSession
(
IUnknown * pUnkOuter, // [in] controllig IUnknown
REFIID riid, // [in] interface to be requested
WCHAR * pwszDataSource, // [in] datasource path
IUnknown ** ppUnk // [out] session interface
)
{
HRESULT hr = E_FAIL;
IDBCreateSession * pIDBCreateSession = NULL;
if( BOT_SESSION == m_pObj->GetBaseObjectType() )
{
// Obtain an instance of the current session Session::IBindResource
// pUnkOuter is always ignored when the DSO already exists
TESTC(hr = ((CDBSession*)m_pObj)->QueryInterface(riid, (void**)ppUnk));
}
else
{
// bind a DSO first
TESTC(hr = BindDSO(NULL, IID_IDBCreateSession, FALSE, pwszDataSource,
(IUnknown**)&pIDBCreateSession));
// Create Session.
TESTC(hr = pIDBCreateSession->CreateSession(pUnkOuter, riid, (IUnknown**)ppUnk));
}
hr = S_OK;
CLEANUP:
SAFE_RELEASE(pIDBCreateSession);
return hr;
}
// CImpIBindResource::BindSession --------------------------------------------
//
// @mfunc Returns an implicit session object
//
// @rdesc
// @flag S_OK | Method succeeded
// @flag OTHER | Other HRESULTs returned by called functions
//
HRESULT CImpIBindResource::BindSession
(
DBIMPLICITSESSION * pImplSession, // [in|out] implicit session pointer
WCHAR * pwszDataSource // [in] DataSource path name
)
{
HRESULT hr = E_FAIL;
IDBCreateSession * pIDBCreateSession = NULL;
// check arguments
if( !pImplSession || !pImplSession->piid )
{
hr = E_INVALIDARG;
goto CLEANUP;
}
if( pImplSession->pUnkOuter && IID_IUnknown != *(pImplSession->piid) )
{
hr = DB_E_NOAGGREGATION;
goto CLEANUP;
}
// This method should not be called when on a session's
// implementation of IBindResource.
// pImplSession should just be ignored in this case
if( BOT_SESSION == m_pObj->GetBaseObjectType() )
return E_FAIL;
// bind a DSO first
TESTC(hr = BindDSO(NULL, IID_IDBCreateSession, FALSE, pwszDataSource,
(IUnknown**)&pIDBCreateSession));
//Create Session.
pImplSession->pSession = NULL;
TESTC(hr = pIDBCreateSession->CreateSession(pImplSession->pUnkOuter,
*(pImplSession->piid), (IUnknown**)&pImplSession->pSession));
hr = S_OK;
CLEANUP:
if (FAILED(hr))
pImplSession->pSession = NULL;
SAFE_RELEASE(pIDBCreateSession);
return hr;
}
// CImpIBindResource::BindRowset ---------------------------------------------
//
// @mfunc Retrieves a rowset object
//
// @rdesc Returns one of the following values:
// @flag S_OK | Method Succeeded
// @flag DB_E_NOTFOUND | Object does not exist
// @flag OTHER | Other HRESULTs returned by called functions
//
HRESULT CImpIBindResource::BindRowset
(
IUnknown * pUnkOuter, // [in] controllig IUnknown
REFIID riid, // [in] interface to be requested
DBIMPLICITSESSION * pImplSession, // [in|out] implicit session pointer
WCHAR * pwszDataSource, // [in] DataSource path name
WCHAR * pwszFile, // [in] URL name
IUnknown ** ppUnk // [out] session interface
)
{
HRESULT hr = E_FAIL;
IOpenRowset * pIOpenRowset = NULL;
DBID TableID;
if( BOT_SESSION != m_pObj->GetBaseObjectType() && pImplSession )
{
TESTC(hr = BindSession(pImplSession, pwszDataSource));
TESTC(hr = pImplSession->pSession->QueryInterface(IID_IOpenRowset, (void**)&pIOpenRowset));
}
else
TESTC(hr = BindSession(NULL, IID_IOpenRowset, pwszDataSource, (IUnknown**)&pIOpenRowset));
TableID.eKind = DBKIND_NAME;
TableID.uName.pwszName = pwszFile;
TESTC(hr = pIOpenRowset->OpenRowset(pUnkOuter, &TableID, NULL, riid,
0, NULL, ppUnk));
hr = S_OK;
CLEANUP:
if( DB_E_NOTABLE == hr )
hr = DB_E_NOTFOUND;
SAFE_RELEASE(pIOpenRowset);
return hr;
}
// CImpIBindResource::BindRow ------------------------------------------------
//
// @mfunc Retrieves a row object
//
// @rdesc Returns one of the following values:
// @flag S_OK | Method Succeeded
// @flag DB_E_NOTFOUND | Object does not exist
// @flag OTHER | Other HRESULTs returned by called functions
//
HRESULT CImpIBindResource::BindRow
(
IUnknown * pUnkOuter, // [in] controllig IUnknown
REFIID riid, // [in] interface to be requested
DBIMPLICITSESSION * pImplSession, // [in|out] implicit session pointer
WCHAR * pwszDataSource, // [in] DataSource path name
WCHAR * pwszFile, // [in] URL name
ULONG ulRowNum, // [in] Row number to retrieve
IUnknown ** ppUnk // [out] session interface
)
{
HRESULT hr = E_FAIL;
CDBSession * pCSession = NULL;
CFileIO * pFileio = NULL;
CRow * pCRow = NULL;
if( BOT_SESSION != m_pObj->GetBaseObjectType() && pImplSession )
{
TESTC(hr = BindSession(pImplSession, pwszDataSource));
TESTC(hr = pImplSession->pSession->QueryInterface(IID_IUnknown, (void**)&pCSession));
}
else
TESTC(hr = BindSession(NULL, IID_IUnknown, pwszDataSource, (IUnknown**)&pCSession));
//Try to open the file...
TESTC(hr = pCSession->m_pCDataSource->OpenFile(pwszFile, &pFileio));
// If no row number specified, just fetch the first 1
if( ulRowNum == 0 )
ulRowNum = 1;
if( pFileio->GetRowCnt() < ulRowNum )
{
hr = DB_E_NOTFOUND;
goto CLEANUP;
}
pCRow = new CRow(pUnkOuter);
if( !pCRow || !pCRow->FInit(pCSession, pFileio, ulRowNum) )
{
hr = E_OUTOFMEMORY;
goto CLEANUP;
}
TESTC(hr = pCRow->QueryInterface(riid, (LPVOID*)ppUnk));
CLEANUP:
if( FAILED(hr) )
{
if( DB_E_NOTABLE == hr )
hr = DB_E_NOTFOUND;
SAFE_DELETE(pCRow);
}
SAFE_RELEASE(pCSession);
return hr;
}
// CImpIBindResource::BindStream ---------------------------------------------
//
// @mfunc Retrieves a stream object
//
// @rdesc Returns one of the following values:
// @flag S_OK | Method Succeeded
// @flag DB_E_NOTFOUND | Object does not exist
// @flag OTHER | Other HRESULTs returned by called functions
//
HRESULT CImpIBindResource::BindStream
(
IUnknown * pUnkOuter, // [in] controllig IUnknown
REFIID riid, // [in] interface to be requested
DBIMPLICITSESSION * pImplSession, // [in|out] implicit session pointer
WCHAR * pwszDataSource, // [in] DataSource path name
WCHAR * pwszFile, // [in] URL name
ULONG ulRowNum, // [in] Row number to retrieve
IUnknown ** ppUnk // [out] session interface
)
{
HRESULT hr = E_FAIL;
CRow * pCRow = NULL;
CStream * pCStream = NULL;
TESTC(hr = BindRow(NULL, IID_IUnknown, pImplSession, pwszDataSource,
pwszFile, ulRowNum, (IUnknown **)&pCRow));
pCStream = new CStream(pUnkOuter);
if( pCStream && pCStream->FInit(pCRow, pCRow->GetRowBuff()) )
hr = pCStream->QueryInterface(riid, (LPVOID *)ppUnk);
else
hr = E_OUTOFMEMORY;
CLEANUP:
if( FAILED(hr) )
{
if( DB_E_NOTABLE == hr )
hr = DB_E_NOTFOUND;
SAFE_DELETE(pCStream);
}
SAFE_RELEASE(pCRow);
return hr;
}
// CImpIBindResource::ValidateBindArgs ---------------------------------------
//
// @mfunc Decrements a persistence count for the object and if
// persistence count is 0, the object destroys itself.
//
// @rdesc HRESULT indicating the status of the method
// @flag S_OK | Method succeeded
// @flag DB_E_NOAGGREGATION | valid pUnkOuter but riid != IID_IUnknown
// @flag E_INVALIDARG | One or more arguments are invalid.
// @flag E_NOINTERFACE | riid == IID_NULL
//
HRESULT CImpIBindResource::ValidateBindArgs
(
IUnknown * pUnkOuter,
LPCOLESTR pwszURL,
DBBINDURLFLAG dwBindFlags,
REFGUID rguid,
REFIID riid,
DBIMPLICITSESSION * pImplSession,
IAuthenticate * pAuthenticate,
DWORD * pdwBindStatus,
IUnknown ** ppUnk
)
{
// Check in-params and NULL out-params in case of error
*pdwBindStatus = DBBINDURLSTATUS_S_OK;
if ( ppUnk )
*ppUnk = NULL;
if( !ppUnk || !pwszURL )
return E_INVALIDARG;
if( pUnkOuter && riid != IID_IUnknown )
return DB_E_NOAGGREGATION;
if( riid == IID_NULL )
return E_NOINTERFACE;
if( dwBindFlags == 0 )
return E_INVALIDARG;
if( pImplSession )
{
if( pImplSession->piid == NULL )
{
return E_INVALIDARG;
}
if( pImplSession->pUnkOuter && (*(pImplSession->piid) != IID_IUnknown) )
{
return DB_E_NOAGGREGATION;
}
}
// Special cases - Detect invalid or unsupported flags
// WAITFORINIT is only valid for DBGUID_DSO
if( rguid != DBGUID_DSO && (dwBindFlags & DBBINDURLFLAG_WAITFORINIT) )
return E_INVALIDARG;
// OUTPUT flag is ignored when binding to DBGUID_ROWSET
if( rguid != DBGUID_ROWSET && (dwBindFlags & DBBINDURLFLAG_OUTPUT) )
return E_INVALIDARG;
// WAITFORINIT and OUTPUT have been handled
// Sample Provider has no notion of a hierarchy, so the recursive flag is always ignored
dwBindFlags &= ~(DBBINDURLFLAG_WAITFORINIT | DBBINDURLFLAG_OUTPUT | DBBINDURLFLAG_RECURSIVE);
if( dwBindFlags &
~(DBBINDURLFLAG_READWRITE | DBBINDURLFLAG_SHARE_DENY_NONE | DBBINDURLFLAG_SHARE_EXCLUSIVE) )
{
if( dwBindFlags & DBBINDURLFLAG_ASYNCHRONOUS )
{
return DB_E_ASYNCNOTSUPPORTED;
}
else
return E_INVALIDARG;
}
// Allow the bind to succeed, but warn user
if( dwBindFlags & DBBINDURLFLAG_SHARE_EXCLUSIVE )
{
*pdwBindStatus = DBBINDURLSTATUS_S_DENYTYPENOTSUPPORTED;
}
if( rguid == DBGUID_DSO || rguid == DBGUID_SESSION )
{
if( dwBindFlags & ~(DBBINDURLFLAG_READ) )
{
return E_INVALIDARG;
}
}
else if( rguid == DBGUID_ROW || rguid == DBGUID_ROWSET )
{
NULL;
}
else if( rguid == DBGUID_STREAM )
{
// Sample Provider's Streams are read only
if( dwBindFlags & DBBINDURLFLAG_WRITE )
return DB_E_READONLY;
}
else
{
// invalid rguid
return DB_E_NOTSUPPORTED;
}
return S_OK;
}
// CImpIBindResource::ParseURL -----------------------------------------------
//
// @mfunc Parses the URL for tablename and row number information
//
// @rdesc HRESULT indicating the status of the method
// @flag S_OK | Method succeeded
// @flag DB_E_NOTFOUND | The object does not exist
//
HRESULT CImpIBindResource::ParseURL
(
LPCOLESTR pwszURL,
WCHAR ** ppwszDataSource,
WCHAR ** ppwszTableName,
ULONG * pulRowNum
)
{
// parse the URL for destination file.
// The sample provider recognizes URLs of the form
// sampprov: [datasource=c:\oledbtst], file=customer.csv, [row=n]
//
// The datasource keyword is ignored when using a session object's
// IBindResource implementation.
const WCHAR * pwsz = NULL;
WCHAR * pwszRowNum = NULL;
WCHAR * pwszStop = NULL;
ULONG cchPrefix = (sizeof(SAMPPROV_URL_PREFIX)-sizeof(WCHAR))/sizeof(WCHAR);
if( !pwszURL )
return E_INVALIDARG;
// Check that the prefix is of the form "sampprov:..."
if( 0 != _wcsnicmp(pwszURL, SAMPPROV_URL_PREFIX, cchPrefix) ||
L':' != *(pwszURL+cchPrefix) )
return DB_E_NOTFOUND;
pwsz = pwszURL+cchPrefix;
while ( iswspace(*pwsz) )
pwsz++;
FindKeyword(pwsz, g_wszDataSourceKeyword, ppwszDataSource);
FindKeyword(pwsz, g_wszFileKeyword, ppwszTableName);
if( FindKeyword(pwsz, g_wszRowKeyword, &pwszRowNum) )
{
*pulRowNum = wcstol(pwszRowNum, &pwszStop, 10);
if( pwszStop && pwszStop[0] != L'\0' )
{
delete [] pwszRowNum;
return DB_E_NOTFOUND;
}
delete [] pwszRowNum;
}
return S_OK;
}
// CImpIBindResource::FindKeyword---------------------------------------------
//
// @mfunc Extracts a keyword value
//
// @rdesc BOOL
// @flag TRUE | Found a keyword value
// @flag FALSE | Failed to find a value
//
BOOL CImpIBindResource::FindKeyword
(
LPCOLESTR pwszURL,
LPCOLESTR pwszKeyword,
WCHAR ** ppwszToken
)
{
assert( pwszKeyword && pwszURL && ppwszToken );
while( *pwszURL )
{
const WCHAR* p1 = pwszURL;
const WCHAR* p2 = pwszKeyword;
while(*p1 && *p2 && (towlower(*p1)==towlower(*p2)) )
p1++, p2++;
if( !*p2 )
{
const WCHAR* pTokBegin = NULL;
const WCHAR* pTokEnd = NULL;
pTokBegin = pwszURL + wcslen(pwszKeyword);
while( iswspace(*pTokBegin) )
pTokBegin++;
if( *pTokBegin == L'=' )
{
pTokBegin += 1;
while( iswspace(*pTokBegin) )
pTokBegin++;
pTokEnd = pTokBegin;
while( *pTokEnd && *pTokEnd != L',' )
pTokEnd++;
*ppwszToken = new WCHAR [pTokEnd - pTokBegin + 1];
if( !ppwszToken )
return FALSE;
StringCchCopyNW(*ppwszToken,pTokEnd - pTokBegin + 1,pTokBegin, pTokEnd - pTokBegin);
*(*ppwszToken + (pTokEnd - pTokBegin)) = L'\0';
return TRUE;
}
return FALSE;
}
pwszURL++;
}
return FALSE;
}
// CImpIBindResource::Bind ---------------------------------------------------
//
// @mfunc Retrieves an interface pointer to service a URL
//
// @rdesc Returns one of the following values:
// @flag S_OK | Method Succeeded
// @flag DB_S_ERRORSOCCURED | Some bind flags were not satisfied
// @flag DB_E_NOTFOUND | The object does not exist
// @flag E_INVALIDARG | pwszURL or ppUnk were NULL
// @flag OTHER | Other HRESULTs returned by called functions
//
STDMETHODIMP CImpIBindResource::Bind
(
IUnknown * pUnkOuter,
LPCOLESTR pwszURL,
DBBINDURLFLAG dwBindFlags,
REFGUID rguid,
REFIID riid,
IAuthenticate * pAuthenticate,
DBIMPLICITSESSION * pImplSession,
DBBINDURLSTATUS * pdwBindStatus,
IUnknown ** ppUnk
)
{
HRESULT hr;
WCHAR * pwszDataSource = NULL;
WCHAR * pwszFile = NULL;
ULONG ulRowNum = 0;
DBBINDURLSTATUS dwBindStatus = DBBINDURLSTATUS_S_OK;
// Ignore pImplSession when binding to a DSO
// Also, on a session object, always ignore pImplSession
if( BOT_SESSION == m_pObj->GetBaseObjectType() ||
rguid == DBGUID_DSO )
pImplSession = NULL;
// On a session object, ignore pUnkOuter when binding to
// objects that already exist
if( BOT_SESSION == m_pObj->GetBaseObjectType() &&
(rguid == DBGUID_DSO || rguid == DBGUID_SESSION) )
pUnkOuter = NULL;
if( !pdwBindStatus )
pdwBindStatus = &dwBindStatus;
// When implemented on a session object, a more functional
// provider would examine it's DBPROP_INIT_MODE and DBPROP_INIT_BINDFLAGS
// properties to determine if it should use its inherited binding
// options. In the case of the sample provider, there are no
// binding options to inherit.
// Validate the Bind Arguments
TESTC(hr = ValidateBindArgs(pUnkOuter, pwszURL, dwBindFlags, rguid,
riid, pImplSession, pAuthenticate, pdwBindStatus, ppUnk));
// Parse the URL for binding information
// Ignore datasource keyword for now...
TESTC(hr = ParseURL(pwszURL, &pwszDataSource, &pwszFile, &ulRowNum));
if( rguid == DBGUID_DSO )
{
TESTC(hr = BindDSO(pUnkOuter, riid, dwBindFlags & DBBINDURLFLAG_WAITFORINIT,
pwszDataSource, ppUnk));
}
else if( rguid == DBGUID_SESSION )
{
TESTC(hr = BindSession(pUnkOuter, riid, pwszDataSource, ppUnk));
}
else if( rguid == DBGUID_ROWSET )
{
if( 0 != ulRowNum)
{
hr = DB_E_NOTCOLLECTION;
goto CLEANUP;
}
TESTC(hr = BindRowset(pUnkOuter, riid, pImplSession, pwszDataSource, pwszFile, ppUnk));
}
else if( rguid == DBGUID_ROW )
{
TESTC(hr = BindRow(pUnkOuter, riid, pImplSession, pwszDataSource, pwszFile, ulRowNum, ppUnk));
}
else if( rguid == DBGUID_STREAM )
{
TESTC(hr = BindStream(pUnkOuter, riid, pImplSession, pwszDataSource, pwszFile, ulRowNum, ppUnk));
}
else
{
assert(!"Bad rguid type not detected!");
}
CLEANUP:
if( pwszDataSource )
delete [] pwszDataSource;
if( pwszFile )
delete [] pwszFile;
if( FAILED(hr) && ppUnk )
{
*ppUnk = NULL;
}
// Bind status is only set on DB_S_ERRORSOCCURRED
if( hr == S_OK )
{
if( *pdwBindStatus )
hr = DB_S_ERRORSOCCURRED;
}
else
*pdwBindStatus = DBBINDURLSTATUS_S_OK;;
return hr;
}
// ICreateRow specific interface methods
// CImpICreateRow::CreateRow -------------------------------------------------
//
// @mfunc Retrieves an interface pointer to service a URL
//
// @rdesc Returns one of the following values:
// @flag E_NOINTERFACE | Sample provider does not support
// ICreateRow
//
STDMETHODIMP CImpICreateRow::CreateRow
(
IUnknown * pUnkOuter,
LPCOLESTR pwszURL,
DBBINDURLFLAG dwBindFlags,
REFGUID rguid,
REFIID riid,
IAuthenticate * pAuthenticate,
DBIMPLICITSESSION * pImplSession,
DBBINDURLSTATUS * pdwBindStatus,
LPOLESTR * ppwszNewURL,
IUnknown ** ppUnk
)
{
// ICreateRow is a mandatory interface on Provider Binders
// Although there is no support for object creation, the Sample Provider
// must support this interface and simply return E_NOINTERFACE
return E_NOINTERFACE;
}
// IDBBinderProperties specific interface methods
// CImpIDBBinderProperties::GetProperties ------------------------------------
//
// @mfunc Returns current settings of all properties in the FLAGS_DATASRCINF
// property group
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_INVALIDARG | pcProperties or prgPropertyInfo was NULL
// @flag E_OUTOFMEMORY | Out of memory
//
STDMETHODIMP CImpIDBBinderProperties::GetProperties
(
ULONG cPropertySets,
const DBPROPIDSET* rgPropertySets,
ULONG* pcPropertySets,
DBPROPSET** prgPropertySets
)
{
assert( m_pObj );
assert( m_pObj->m_pUtilProp );
HRESULT hr = m_pObj->m_pUtilProp->GetPropertiesArgChk(PROPSET_DSO, cPropertySets,
rgPropertySets, pcPropertySets, prgPropertySets);
if ( FAILED(hr) )
return hr;
// Just pass this call on to the utility object that manages our properties
return m_pObj->m_pUtilProp->GetProperties(
PROPSET_DSO,
cPropertySets,
rgPropertySets,
pcPropertySets,
prgPropertySets );
}
// CImpIDBBinderProperties::GetPropertyInfo ---------------------------------
//
// @mfunc Returns information about rowset and data source properties supported
// by the provider
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_INVALIDARG | pcPropertyInfo or prgPropertyInfo was NULL
// @flag E_OUTOFMEMORY | Out of memory
//
STDMETHODIMP CImpIDBBinderProperties::GetPropertyInfo
(
ULONG cPropertySets,
const DBPROPIDSET* rgPropertySets,
ULONG* pcPropertyInfoSets,
DBPROPINFOSET** prgPropertyInfoSets,
WCHAR** ppDescBuffer
)
{
assert( m_pObj );
assert( m_pObj->m_pUtilProp );
// just pass this call on to the utility object that manages our properties
return m_pObj->m_pUtilProp->GetPropertyInfo(
FALSE,
cPropertySets,
rgPropertySets,
pcPropertyInfoSets,
prgPropertyInfoSets,
ppDescBuffer);
}
// CImpIDBBinderProperties::SetProperties --------------------------------------
//
// @mfunc Set properties in the FLAGS_DATASRCINF property group
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_INVALIDARG | cProperties was not equal to 0 and rgProperties was NULL
//
STDMETHODIMP CImpIDBBinderProperties::SetProperties
(
ULONG cPropertySets, //@parm IN | Count of structs returned
DBPROPSET rgPropertySets[] //@parm IN | Array of Properties
)
{
HRESULT hr = E_FAIL;
//
// Asserts
//
assert( m_pObj );
assert( m_pObj->m_pUtilProp );
//
// Quick return if the Count of cPropertySets is 0
//
if( cPropertySets == 0 )
return S_OK;
//
// Check in-params and NULL out-params in case of error
//
hr=m_pObj->m_pUtilProp->SetPropertiesArgChk(cPropertySets, rgPropertySets);
if( FAILED(hr) )
return hr;
//
// just pass this call on to the utility object that manages our properties
//
return m_pObj->m_pUtilProp->SetProperties(PROPSET_DSO,
cPropertySets, rgPropertySets);
}
// CImpIDBBinderProperties::Reset ----------------------------------------------
//
// @mfunc Reset properties to their default value
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_OUTOFMEMORY | Out of memory
//
STDMETHODIMP CImpIDBBinderProperties::Reset()
{
PCUTILPROP pCUtilProp = NULL;
pCUtilProp = new CUtilProp();
if( !pCUtilProp )
return E_OUTOFMEMORY;
SAFE_DELETE( m_pObj->m_pUtilProp );
m_pObj->m_pUtilProp = pCUtilProp;
return S_OK;
}