#include #include #include #define DBINITCONSTANTS #include #undef DBINITCONSTANTS #include #include "simpledb.h" // // CSimpleDatabase // CSimpleDatabase::CSimpleDatabase( void ) : m_bCreated(false), m_bSession(false) { HRESULT hr; CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); hr = CoCreateInstance( CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER, IID_IDataInitialize, (PVOID *)&m_pDataInit ); if ( !FAILED(hr) ) { m_bCreated = TRUE; } } CSimpleDatabase::~CSimpleDatabase( void ) { if ( NULL != m_pDataInit ) { m_pDataInit->Release(); } if ( NULL != m_pSession ) { m_pSession->Release(); } CoUninitialize(); } HRESULT CSimpleDatabase::Connect( LPCTSTR szServer, LPCTSTR szDatabase, LPCTSTR szUserName, LPCTSTR szPassword ) { HRESULT hr; DBPROP props[4]; DBPROPSET rgProps[1]; DWORD dwNumProps = 0; IDBInitialize *pDBInitialize; IDBProperties *pDBProps; #ifndef UNICODE wchar_t *wszTemp; size_t lenTemp; #endif if ( !m_bCreated ) { return E_HANDLE; } // If this is not the first connection, reset if ( m_bSession ) { m_pSession->Release(); m_pSession = NULL; m_bSession = FALSE; } // // Set the connection properties // for ( short i = 0; i < 4; i++ ) { VariantInit( &props[i].vValue ); } // Server props[0].dwPropertyID = DBPROP_INIT_DATASOURCE; props[0].vValue.vt = VT_BSTR; #ifndef UNICODE lenTemp = strlen(szServer) + 1; wszTemp = new wchar_t[lenTemp]; if ( NULL == wszTemp ) { return E_OUTOFMEMORY; } if ( 0 == MultiByteToWideChar( _getmbcp(), 0L, szServer, lenTemp, wszTemp, lenTemp ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } props[0].vValue.bstrVal = SysAllocString( wszTemp ); delete [] wszTemp; #else props[0].vValue.bstrVal = SysAllocString( szServer ); #endif props[0].dwOptions = DBPROPOPTIONS_REQUIRED; props[0].colid = DB_NULLID; dwNumProps++; if ( szDatabase ) { // Default Database props[1].dwPropertyID = DBPROP_INIT_CATALOG; props[1].vValue.vt = VT_BSTR; #ifndef UNICODE lenTemp = strlen(szDatabase) + 1; wszTemp = new wchar_t[lenTemp]; if ( NULL == wszTemp ) { return E_OUTOFMEMORY; } if ( 0 == MultiByteToWideChar( _getmbcp(), 0L, szDatabase, lenTemp, wszTemp, lenTemp ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } props[1].vValue.bstrVal = SysAllocString( wszTemp ); delete [] wszTemp; #else props[1].vValue.bstrVal = SysAllocString( szDatabase ); #endif props[1].dwOptions = DBPROPOPTIONS_REQUIRED; props[1].colid = DB_NULLID; dwNumProps++; } if ( szUserName ) { // Username props[2].dwPropertyID = DBPROP_AUTH_USERID; props[2].vValue.vt = VT_BSTR; #ifndef UNICODE lenTemp = strlen(szUserName) + 1; wszTemp = new wchar_t[lenTemp]; if ( NULL == wszTemp ) { return E_OUTOFMEMORY; } if ( 0 == MultiByteToWideChar( _getmbcp(), 0L, szUserName, lenTemp, wszTemp, lenTemp ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } props[2].vValue.bstrVal = SysAllocString( wszTemp ); delete [] wszTemp; #else props[2].vValue.bstrVal = SysAllocString( szUserName ); #endif props[2].dwOptions = DBPROPOPTIONS_REQUIRED; props[2].colid = DB_NULLID; dwNumProps++; // Password props[3].dwPropertyID = DBPROP_AUTH_PASSWORD; props[3].vValue.vt = VT_BSTR; #ifndef UNICODE lenTemp = strlen(szPassword) + 1; wszTemp = new wchar_t[lenTemp]; if ( NULL == wszTemp ) { return E_OUTOFMEMORY; } if ( 0 == MultiByteToWideChar( _getmbcp(), 0L, szPassword, lenTemp, wszTemp, lenTemp ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } props[3].vValue.bstrVal = SysAllocString( wszTemp ); delete [] wszTemp; #else props[3].vValue.bstrVal = SysAllocString( szPassword ); #endif props[3].dwOptions = DBPROPOPTIONS_REQUIRED; props[3].colid = DB_NULLID; dwNumProps++; } else { // Use Windows authentication props[3].dwPropertyID = DBPROP_AUTH_INTEGRATED; props[3].vValue.vt = VT_BSTR; props[3].vValue.bstrVal = NULL; props[3].dwOptions = DBPROPOPTIONS_REQUIRED; props[3].colid = DB_NULLID; dwNumProps++; } hr = m_pDataInit->CreateDBInstance( CLSID_SQLOLEDB, NULL, CLSCTX_INPROC_SERVER, NULL, IID_IDBInitialize, (IUnknown **)&pDBInitialize ); if ( FAILED(hr) ) { return hr; } hr = pDBInitialize->QueryInterface( IID_IDBProperties, (PVOID *)&pDBProps ); if ( FAILED(hr) ) { return hr; } rgProps[0].guidPropertySet = DBPROPSET_DBINIT; rgProps[0].cProperties = dwNumProps; rgProps[0].rgProperties = props; hr = pDBProps->SetProperties(1, rgProps); pDBProps->Release(); if ( FAILED(hr) ) { return hr; } hr = pDBInitialize->Initialize(); if ( FAILED(hr) ) { pDBInitialize->Release(); return hr; } hr = EstablishSession( pDBInitialize ); pDBInitialize->Release(); return hr; } HRESULT CSimpleDatabase::EstablishSession( IDBInitialize *pDBInitialize ) { HRESULT hr; IDBCreateSession *pCreateSession = NULL; hr = pDBInitialize->QueryInterface( IID_IDBCreateSession, (PVOID *)&pCreateSession ); if ( FAILED(hr) ) { return hr; } hr = pCreateSession->CreateSession( NULL, IID_IDBCreateCommand, (IUnknown **)&m_pSession ); if ( FAILED(hr) ) { pCreateSession->Release(); return hr; } pCreateSession->Release(); m_bSession = FALSE; return S_OK; } HRESULT CSimpleDatabase::Execute( LPCTSTR szCommand, CSimpleDBResults **ppOutResults ) { HRESULT hr; ICommandText *pCommandText = NULL; IMultipleResults *pResults = NULL; DBROWCOUNT cRowsAffected; if ( NULL != ppOutResults ) { *ppOutResults = NULL; } hr = m_pSession->CreateCommand( NULL, IID_ICommandText, (IUnknown **)&pCommandText ); if ( FAILED(hr) ) { return hr; } #ifndef UNICODE size_t lenTemp = strlen(szCommand) + 1; wchar_t *wszTemp = new wchar_t[lenTemp]; if ( NULL == wszTemp ) { return E_OUTOFMEMORY; } if ( 0 == MultiByteToWideChar( _getmbcp(), 0L, szCommand, lenTemp, wszTemp, lenTemp ) ) { pCommandText->Release(); return HRESULT_FROM_WIN32( GetLastError() ); } hr = pCommandText->SetCommandText( DBGUID_DBSQL, wszTemp ); delete [] wszTemp; #else hr = pCommandText->SetCommandText( DBGUID_DBSQL, szCommand ); #endif if ( FAILED(hr) ) { pCommandText->Release(); return hr; } hr = pCommandText->Execute( NULL, IID_IMultipleResults, NULL, &cRowsAffected, (IUnknown **)&pResults ); if ( FAILED(hr) ) { pCommandText->Release(); return hr; } // If the command succeeded but didn't return any results, return successfully if ( cRowsAffected != -1 ) { return S_FALSE; } *ppOutResults = new CSimpleDBResults( pResults ); pResults->Release(); if ( NULL == *ppOutResults ) { return E_OUTOFMEMORY; } return S_OK; } // // CSimpleDBResults // CSimpleDBResults::CSimpleDBResults( IMultipleResults *pResults ) : m_pResults(NULL), m_pCurRowset(NULL), m_phRow(NULL), m_rgColumnInfo(NULL), m_pColumnBuf(NULL), m_colInfo(NULL), m_numColumns(0) { m_pResults = pResults; m_pResults->AddRef(); NextResultSet(); } CSimpleDBResults::~CSimpleDBResults( void ) { FreeRow(); FreeRowset(); m_pResults->Release(); } HRESULT CSimpleDBResults::NextResultSet( void ) { HRESULT hr; DBROWCOUNT cRowsAffected; IColumnsInfo *pColInfo = NULL; FreeRowset(); hr = m_pResults->GetResult( NULL, 0, IID_IRowset, &cRowsAffected, (IUnknown **)&m_pCurRowset ); if ( FAILED(hr) ) { return hr; } // Store column info hr = m_pCurRowset->QueryInterface( IID_IColumnsInfo, (PVOID *)&pColInfo ); if ( FAILED(hr) ) { return hr; } hr = pColInfo->GetColumnInfo( &m_numColumns, &m_rgColumnInfo, &m_pColumnBuf ); pColInfo->Release(); if ( FAILED(hr) ) { return hr; } m_colInfo = new ColInfo[m_numColumns]; if ( NULL == m_colInfo ) { return E_OUTOFMEMORY; } memset( (PVOID)m_colInfo, 0, sizeof(ColInfo) * m_numColumns ); return S_OK; } void CSimpleDBResults::FreeRowset( void ) { IAccessor *pAccessor = NULL; if ( m_pCurRowset ) { if ( FAILED(m_pCurRowset->QueryInterface( IID_IAccessor, (PVOID *)&pAccessor )) ) { pAccessor = NULL; } } if ( NULL != m_rgColumnInfo ) { CoTaskMemFree( m_rgColumnInfo ); m_rgColumnInfo = NULL; } if ( NULL != m_pColumnBuf ) { CoTaskMemFree( m_pColumnBuf ); m_pColumnBuf = NULL; } if ( NULL != m_colInfo ) { for ( DWORD i = 0; i < m_numColumns; i++ ) { #ifndef UNICODE if ( NULL != m_colInfo[i].szColumnName ) { delete [] m_colInfo[i].szColumnName; } #endif if ( pAccessor && m_colInfo[i].hAccessor ) { pAccessor->ReleaseAccessor( m_colInfo[i].hAccessor, NULL ); } } delete [] m_colInfo; m_colInfo = NULL; } if ( pAccessor ) { pAccessor->Release(); } if ( m_pCurRowset ) { m_pCurRowset->Release(); } m_numColumns = 0; } void CSimpleDBResults::FreeRow( void ) { if ( NULL != m_phRow ) { m_pCurRowset->ReleaseRows( 1, m_phRow, NULL, NULL, NULL ); m_phRow = NULL; } } HRESULT CSimpleDBResults::NextRow( void ) { HRESULT hr; DBCOUNTITEM cRowsReturned; FreeRow(); hr = m_pCurRowset->GetNextRows( DB_NULL_HCHAPTER, 0, 1, &cRowsReturned, &m_phRow ); if ( DB_S_ENDOFROWSET == hr ) { return S_FALSE; } else if ( FAILED(hr) ) { return hr; } return S_OK; } HRESULT CSimpleDBResults::GetFieldValue( LPCTSTR szField, LPTSTR szValue, DWORD dwMaxChars ) { HRESULT hr; DWORD col; IAccessor *pAccessor = NULL; DBBINDING rgBindings[1]; DBBINDSTATUS rgStatus[1]; PVOID pBuf; szValue[0] = _T('\0'); // Look through column names for specified field for ( col = 0; col < m_numColumns; col++ ) { TCHAR *szColName; #ifndef UNICODE if ( NULL == m_colInfo[col].szColumnName ) { size_t lenName = wcslen(m_rgColumnInfo[col].pwszName) + 1; m_colInfo[col].szColumnName = new char[lenName]; if ( NULL == m_colInfo[col].szColumnName ) { return E_OUTOFMEMORY; } if ( 0 == WideCharToMultiByte( CP_ACP, 0L, m_rgColumnInfo[col].pwszName, lenName, m_colInfo[col].szColumnName, lenName, NULL, NULL ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } } szColName = m_colInfo[col].szColumnName; #else szColName = m_rgColumnInfo[col].pwszName; #endif if ( !_tcsicmp( szColName, szField ) ) { break; } } // Column is not in current rowset if ( col >= m_numColumns ) { return S_FALSE; } if ( !m_colInfo[col].hAccessor ) { memset( rgBindings, 0, sizeof(DBBINDING) ); rgBindings[0].iOrdinal = m_rgColumnInfo[col].iOrdinal; rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; rgBindings[0].dwFlags = 0; rgBindings[0].obStatus = offsetof(_BindResult, status); rgBindings[0].obLength = offsetof(_BindResult, length); rgBindings[0].obValue = offsetof(_BindResult, value); rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED; rgBindings[0].eParamIO = DBPARAMIO_NOTPARAM; rgBindings[0].bPrecision = m_rgColumnInfo[col].bPrecision; rgBindings[0].bScale = m_rgColumnInfo[col].bScale; rgBindings[0].wType = DBTYPE_WSTR; rgBindings[0].cbMaxLen = dwMaxChars * sizeof(WCHAR); hr = m_pCurRowset->QueryInterface( IID_IAccessor, (PVOID *)&pAccessor ); if ( FAILED(hr) ) { return hr; } hr = pAccessor->CreateAccessor( DBACCESSOR_ROWDATA, 1, rgBindings, 0, &m_colInfo[col].hAccessor, rgStatus ); pAccessor->Release(); if ( FAILED(hr) ) { return hr; } } // Setup a buffer large enough to hold max results pBuf = (PVOID)new BYTE[ sizeof(_BindResult) + dwMaxChars * sizeof(WCHAR) ]; if ( NULL == pBuf ) { return E_OUTOFMEMORY; } hr = m_pCurRowset->GetData( *m_phRow, m_colInfo[col].hAccessor, pBuf ); if ( FAILED(hr) ) { return hr; } // Skip status and length and just get the result for now wchar_t *wszValue = (LPWSTR)((DWORD_PTR)pBuf + offsetof(_BindResult, value)); #ifndef UNICODE if ( 0 == WideCharToMultiByte( CP_ACP, 0L, wszValue, -1, szValue, dwMaxChars, NULL, NULL ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } #else wcscpy( szValue, wszValue ); #endif return S_OK; }