622 lines
16 KiB
C++
622 lines
16 KiB
C++
#include <tchar.h>
|
|
#include <stddef.h>
|
|
#include <mbctype.h>
|
|
#define DBINITCONSTANTS
|
|
#include <sqloledb.h>
|
|
#undef DBINITCONSTANTS
|
|
#include <oledberr.h>
|
|
#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;
|
|
}
|